3

I am executing set of tasks, and in order to span them over time I've used Thread.sleep(forTimeInterval: ... ) It adds pauses between executions.

Then, on the main screen I have controllers, that can intervene into thread execution, so when controller applied I want to cancel the sleep. And start from the place of user's choice. So, I've tried Thread.exit() - and it terminates the program with error.

How to exit (or, refresh) the current thread and start from the place I want? What are the ways to control the suspension of thread by button (i.e. controller)?

What actually happens is that if I cancel, it continues to run just from the same place...

let queue = DispatchQueue(label: "Actions Queue")
let delay: Double = 5
var actions = ["action 1", "action 2", "action 3", "action 4", "action 5"]


// every time task finishes, it calls for the following task (with delay)
queue.sync {
// sets an interval, that continues an action
    Thread.sleep(forTimeInterval: TimeInterval(delay))
    // continue an action
}

// heres how I've tried in main view, but it doesn't work
queue.sync {
    Thread.current.cancel()
}

EDITS:

For example, what does the cancel() do here? and why exit() can't be applied to Thread.current, but only to Thread.

"You can use these semantics to cancel the execution of a thread or determine if the thread is still executing or has finished its task". Okey, if I cancel(). What, then will start it again?

queue.sync {
    Thread.sleep(forTimeInterval: TimeInterval(10.0))
    // do something
}

Button("...") {
    queue.sync {
        Thread.current.cancel()
    }
}

https://developer.apple.com/documentation/foundation/thread

MikeMaus
  • 385
  • 3
  • 22
  • Tell me in the comments, if I have to improve the question; so that I know how I can fix it for better quality discussion – MikeMaus Feb 13 '21 at 18:59
  • 3
    I think you're mixing GCD with Threads. While they're targetting similar goals they are on completely different levels so it's never a good idea to mix them. I'd suggest you to use either [GCD](https://developer.apple.com/documentation/dispatch) with [work items](https://developer.apple.com/documentation/dispatch/dispatchworkitem) or [OperationQueue](https://developer.apple.com/documentation/foundation/operationqueue) with a set of [Operations](https://developer.apple.com/documentation/foundation/operation) if you need more complex interaction between your tasks. – ScorpiCon Feb 13 '21 at 20:12
  • @ScorpiCon what I am trying to achieve is - having a presentation that runs with predetermined time between slides, but if user wants to go back(or forward); it should cut straight away to previous slide and continue in the same manner of predetermined pauses. Do you have some thoughts on this? – MikeMaus Feb 13 '21 at 20:33

1 Answers1

2

As a general rule, I would advise against sleeping on a thread. First, we do not have preemptive cancelation. Second, it’s an inefficient use of resources, tying up that thread unnecessarily.

If you want to do something after a certain period of time, you have a few options:

  1. Schedule a Timer and then invalidate it if you want to stop it.

  2. If using Swift concurrency (e.g., Task, async-await, etc.), you can Task.sleep, which, unlike Thread.sleep, detects and handles cancelation. Thread.sleep should be avoided, but with Swift concurrency, you can store the Task in a property, cancel it when appropriate, and Task.sleep within the Task will handle cancellation elegantly.

  3. You can create a DispatchWorkItem, dispatch it with asyncAfter, and then cancel if you don’t want that to happen.

If you have some cancelable tasks that you want to perform every x seconds, a single repeating Timer is probably easiest, as you can invalidate it and it stops the whole repeating series in one step. (It also avoids timer coalescing problems.)


You said:

what I am trying to achieve is - having a presentation that runs with predetermined time between slides, but if user wants to go back (or forward); it should cut straight away to previous slide and continue in the same manner of predetermined pauses.

I would suggest a repeating Timer to advance to the next slide. If the user manually changes to another slide, invalidate the old timer and create a new repeating Timer.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Thank you for answer and links to research reading! Made it to me way more clear! Currently trying to implement properly this functionality with Timer. The response time of the program 1000x times faster than with Threading. – MikeMaus Feb 14 '21 at 01:58
  • 1
    Cool. FWIW, GCD pattern shouldn't be slower, but for something repeating that you want to cancel, `Timer` is just a much easier way to do it. There probably was something else going on in your GCD implementation, but I guess it doesn't matter now that you've got a better solution cooking... – Rob Feb 14 '21 at 02:09