如何在 swift 中取消线程

问题描述 投票:0回答:1

我遇到了一个类实例没有被释放的问题,所以应用程序卡住了。导致问题的课程是

import Foundation

class ResponseTimeoutQueue{

    private let mMsgOut: [UInt8]

    private let mResponseMsgId: Int

    private let mTimeoutMilliSec: UInt32

    private let mNumRetries: Int

    private var timeoutWorkItem: DispatchWorkItem?

    init(responseMsgId: Int, msgOut: [UInt8], timeoutMilliSec: UInt32, numRetries: Int) {
        mResponseMsgId = responseMsgId
        mMsgOut = msgOut
        mTimeoutMilliSec = timeoutMilliSec
        mNumRetries = numRetries
    }

    func run() {
    
        // create a work item with the custom code
        timeoutWorkItem = DispatchWorkItem {
                 // Insert your code here
           
               var retryNum: Int = 0
               var doRetry: Bool = true
               while (doRetry) {
                   Thread.sleep(forTimeInterval: TimeInterval(self.mTimeoutMilliSec))
                   // If we are here then it means the last send did not receive a response before
                   // timing out.  Write with no timeout or num retries so we don't spawn another
                   // ResponseTimeoutQueue.
     

                   retryNum += 1
                   if (retryNum <= self.mNumRetries) {
                       SessionController.sharedController.invokeWriteData(responseMsgId: self.mResponseMsgId, bytes: self.mMsgOut)
                   } else {
                       doRetry = false
                   }
               }
               // Notify the handler.
               NotificationCenter.default.post(name: .timeOutMessage, object: -1)
           }

          //Create dispatch group
           let dispatchGroup = DispatchGroup()

          // execute the workItem with dispatchGroup
           DispatchQueue.global().async(group: dispatchGroup, execute: timeoutWorkItem!)

          //Handle code after the completion of global queue
           dispatchGroup.notify(queue: DispatchQueue.global()) {
               }

            timeoutWorkItem?.cancel()
    }

    func interrupt() {
        timeoutWorkItem?.cancel()
        timeoutWorkItem = nil
    }
}

run()函数的调用发生在

func writeNotify(responseMsgId: Int, buffer: [UInt8], timeoutMilliSec: UInt32, numRetries: Int) {
    if (timeoutMilliSec > 0) {
        mResponseMonitorThreadMap[responseMsgId]?.interrupt()
        let timeoutThread: ResponseTimeoutQueue =
        ResponseTimeoutQueue(responseMsgId: responseMsgId, msgOut: buffer,
                             timeoutMilliSec: timeoutMilliSec, numRetries: numRetries)
        
        timeoutThread.run()
        mResponseMonitorThreadMap[responseMsgId] = timeoutThread
    }
}

基本上我们从雷达请求数据,当我们得到数据时我们调用

func cancelResponseTimeout(responseMsgId: Int) {
    mResponseMonitorThreadMap[responseMsgId]?.interrupt()
    if mResponseMonitorThreadMap.keys.contains(responseMsgId){
        mResponseMonitorThreadMap[responseMsgId] = nil
    }
}

但在与雷达通信几分钟后,responseTimeoutQueue 线程数为 65 或更多。我注释了writeToNotify()函数,那么应用就没有问题了。我将附上内存层次结构屏幕截图。我尝试在调用 timeoutThread.run() 后给出

timeoutThread = nil
,但类实例编号没有改变。如何解决这个问题?提前致谢。

ios swift automatic-ref-counting swift5
1个回答
0
投票

我可以在这里看到许多问题。第一个也是最重要的是在这一行:

Thread.sleep(forTimeInterval: TimeInterval(self.mTimeoutMilliSec))

A

TimeInterval
Double
的别名,它代表 seconds 的数量。如果你想睡 500 毫秒,你需要
TimeInterval(500)/1000
TimeInterval(0.5)
.

我也不确定所有对

cancel()
的调用的意义是什么。
run()
中的那个是竞争条件,因为它可能在工作项开始执行之前被调用。另一个什么都不做,因为
cancel()
只会取消尚未开始执行的项目。

你确实有一个强大的参考循环,但我认为如果你在调度组完成处理程序中将

timeoutWorkItem
设置为
nil
会被破坏。

说到调度组:你只有一个项目,所以你真的不需要它。您可以将完成处理程序直接放在工作项上,并在那里将属性设置为

nil

编辑

OK,再看一眼。最大的问题不是超级长时间的超时,而是

cancel()
没有按照你的想法去做。这是文档

取消会导致未来执行工作项的尝试立即返回。 取消不影响已经开始的工作项的执行.

[我的斜体]

我认为你最好设置一个

NSTimer
DispatchSourceTimer
超时,如果你得到响应则取消它,然后它的事件块可以重试。

© www.soinside.com 2019 - 2024. All rights reserved.