Stop a Dispatchqueue That Is Running on the Main Thread

Stop a DispatchQueue that is running on the main thread

You can use DispatchWorkItems. They can be scheduled on DispatchQueues and cancelled before their execution.

let work = DispatchWorkItem(block: {
self.isShootingOnHold = false
self.shoot()
self.shootingEngine = Timer.scheduledTimer(timeInterval: (Double(60)/Double(self.ratePerMinute)), target: self, selector: #selector(ShootingEnemy.shoot), userInfo: nil, repeats: true)
})
DispatchQueue.main.asyncAfter(deadline: .now() + (delay * Double(isDelayAccounted.hashValue)) + extraDelay, execute: work)
work.cancel()

Why does Dispatchqueue.main.async still excute the block in main thread?

You said:

I know when we use .async to execute the task we won't block the main thread.

Yes, we often dispatch asynchronously to a background queue to avoid blocking the main thread. But, more accurately, we technically use async to avoid blocking the current thread. Sure, if you’re on the main thread, that means we’re not blocking the main thread. But if you’re currently running on a background thread, then async just keeps you from blocking that current background thread.

... but why we use DispatchQueue.main.async?

This is commonly used when you’re already on a background thread, but have something (like a UI update) that must be run on the main thread. Then you’d dispatch that UI update from the background thread back to the main queue. And we’d generally do this asynchronously because there’s no point in having that background thread wait for the UI update.

E.g.

DispatchQueue.global().async {
// do something computationally intensive here ...

// ... but when you want to update the UI with the result, you’d dispatch that back to the main queue

DispatchQueue.main.async {
self.label.text = ...
}
}

Or you’d use the same pattern when using URLSession (or anything that runs on a background thread). We’d use DispatchQueue.main.async if we’re currently on some background thread, but need to perform UI updates, which must always happen on the main thread. So we’d dispatch those UI updates back to the main queue.

That’s why we use DispatchQueue.main.async. That having been said, while there is rarely any utility to it, you technically can dispatch asynchronously from the main thread back to itself, like you have in your question. All that will happen is that the dispatched code will be added to the end of the main queue, but won’t run until you finish whatever you were previously doing on the main thread.

For example, imagine that the following is run on the main thread

print("a")
DispatchQueue.main.async {
print("b")
}
print("c")

You’ll see “a”, the print("b") will be queued (but not run yet), you’ll then carry on the main thread and will see “c”. Then when you eventually yield back to the app’s run loop, only then will the main thread be freed so that print("b") can be performed. So you’ll see “a” and “c”, first, and then “b”!

how to stop a dispatchQueue in swift

I'm not sure if there are best practices here, but I would consider doing what you are doing with a Timer rather than the DispatchQueue.

class GifClass: UIViewController {

@IBOutlet weak var gifImage: UIImageView!
@IBOutlet weak var skipButton: UIButton!

var timer = Timer()

override func viewDidLoad() {
super.viewDidLoad()

gifImage.loadGif(name: "promed")

timer = Timer.scheduledTimer(timeInterval: 11, target: self, selector: #selector(timerAction), userInfo: nil, repeats: false)
}

@objc func timerAction() {
performSegue(withIdentifier: "introLogin", sender: self)
}

@IBAction func skip(_ sender: Any) {
timer.invalidate()
performSegue(withIdentifier: "introLogin", sender: self)
}
}

How to stop execution of a running background thread from main thread on swift while using DispatchQueue

I think the best solution is to execute DispatchWorkItem in async:

DispatchWorkItem encapsulates work that can be performed. A work item can be dispatched onto a DispatchQueue and within a DispatchGroup

so at the end your code might be:

let workItem = DispatchWorkItem {
//.... writing stuff in background ....

DispatchQueue.main.async {
//.... done writing stuff, updating ui ....
}
}
DispatchQueue.global().async(execute: workItem)

when you need to stop the execution just call .cancel():

//.... but, if stuff goes wrong ....
DispatchQueue.main.async {
workItem.cancel()
}

Swift Cancel DispatchQueue Process

There is no way to stop or "kill" a DispatchWorkItem or NSOperation from outside. There is a cancel() method, but that merely sets the isCancelled property of the item or operation to true. This does not stop the execution of the item itself. Ans since recv is blocking, there is no way to check the isCancelled flag during execution. This means the answer posted by Vadian unfortunately wouldn't do anything.

According to the Apple docs on NSOperation.cancel:

This method does not force your operation code to stop.

The same goes for NSOperationQueue.cancelAllOperations:

Canceling the operations does not automatically remove them from the queue or stop those that are currently executing.

You might think it is possible to drop down to using a raw NSThread. However, the same principle applies hier. You cannot deterministically kill a thread from the outside.

Possible solution: timeout

The best solution I can think of is to use the timeout feature of the socket. I don't know where UDPServer comes from, but perhaps it has a built in timeout.

Possible solution: Poor man's timeout (send packet to localhost)

Another option you can try is to send some UDP packets to yourself after a certain time has elapsed. This way, recv will receive some data, and execution will continue. This could possibly be used as a "poor man's timeout".



Related Topics



Leave a reply



Submit