In my application, I've got a background thread which make sure the local database (core data) is synchronized with server. There are multiple ways to trigger the processing (notificationServer observer, timer, ...). However, I want to make sure there is only one instance processing the data at the time. So, if a processing task is triggered while "old" synchronization task is running, I want it to wait for the previous task to finish.
My current code looks something like this:
backgroundContext = persistance.persistentContainer.newBackgroundContext()
// this is an instance variable which will be shared by all the threads
...
...
#objc func managedObjectContextDidSave(notification: NSNotification) {
backgroundContext.perform {
self.processAllHisotory()
}
}
Is it guaranteed that if I perform multiple tasks on the same context, they will not get executed in parallel? If not, what is the best way to synchronize such tasks?
If you make a DispatchQueue, it is a serial queue. A new task cannot start while a task is in progress. In effect, the serial queue is a lock.
Related
Does async operation in iOS, internally create a new thread, and allocate task to it ?
An async operation is capable to internally create a new thread and allocate task to it. But in order for this to happen you need to run an async operation which creates a new thread and allocates task to it. Or in other words: There is no direct correlation.
I assume that by async you mean something like DispatchQueue.main.async { <#code here#> }. This does not create a new thread as main thread should already be present. How and why does this work can be (if oversimplified) explained with an array of operations and an endless loop which is basically what RunLoop is there for. Imagine the following:
Array<Operations> allOperations;
int main() {
bool continueRunning = true;
for(;continueRunning;) {
allOperations.forEach { $0.run(); }
allOperations.clear();
}
return 0;
}
And when you call something like DispatchQueue.main.async it basically creates a new operation and inserts it into allOperations. The same thread will eventually go into a new loop (within for-loop) and call your operation asynchronously. Again keep in mind that this is all over-simplified just to illustrate the idea behind all of it. You can from this also imagine how for instance timers work; the operation will evaluate if current time is greater then the one of next scheduled execution and if so it will trigger the operation on timer. That is also why timers can not be very precise since they depend on rest of execution and thread may be busy.
A new thread on the other hand may be spawned when you create a new queue DispatchQueue(label: "Will most likely run on a new thread"). When(if) exactly will a thread be made is not something that needs to be fixed. It may vary from implementations and systems being run on. The tool will only guarantee to perform what it is designed for but not how it will do it.
And then there is also Thread class which can generate a new thread. But the deal is same as for previous one; it might internally instantly create a new thread or it might do it later, lazily. All it guarantees is that it will work for it's public interface.
I am not saying that these things change over time, implementation or system they run on. I am only saying that they potentially could and they might have had.
Updating UI on a thread other than the main thread is a common mistake that can result in missed UI updates, visual defects, data corruptions, and crashes.
https://developer.apple.com/documentation/code_diagnostics/main_thread_checker
Example:
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if let data = data {
DispatchQueue.main.async { // Correct
self.label.text = "\(data.count) bytes downloaded"
}
}
}
task.resume()
My question starts here -
I am confused with above statement when we say .async means not simultaneously (Or not parallel) with .main. Can someone explain my problem?
DispatchQueue.main.async means you queue up a task in the main queue, without waiting the task to be executed. The main queue tasks will be run on the main thread one by one automatically, scheduled by the OS.
Think of each DispatchQueue as a worker. Calling .async adds a task under the worker's TODO list and do not wait for the worker to finish the task. DispathQueue.main is the specific worker that work on the main thread.
Oh the other hand, .sync will block the thread until the task block has finished executing. You can call .sync on any thread other than the main thread since main thread must not be blocked.
That doesn't means you cannot call DispatchQueue.main.sync. You can call DispatchQueue.main.sync just like any custom dispathQueue.sync on non- main thread.
e.g.
DispatchQueue(label: "bgqueue", qos: .background).async
{
DispatchQueue.main.sync{}
}
is OK.
But
DispatchQueue.main.async{
DispatchQueue.main.sync{}
}
is NOT.
.sync is usually not quite useful. If you want something to happen after a main queue task, you just queue that "something" into the main queue too. It is not worth to block a thread if not necessary.
That being said, here are two rules to remember when using .sync, regardless of which queue is receiving the .sync call :
never call .sync from a queue to itself, which causes deadlock.
never call .sync from main queue, which blocks the UI thread.
I think you are confused how DispatchQueue works.
DispatchQueue simply manages thread pool, and when we give it a block of code to execute it simply picks an idle thread and run that piece of code on it.
So basically one thread can be used by many queues. A queue is simply a task list which manages all the tasks which will execute in future.
So basically here when you are doing DispatchQueue.main.async then you are simply instructing main queue to execute your code without waiting for pending tasks execution.
Please explain to me why I am getting this crash?
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
in this
DispatchQueue.main.sync {
print("sync")
}
This is my code.
override func viewDidLoad() {
super.viewDidLoad()
print("Start")
DispatchQueue.main.async {
print("async")
}
DispatchQueue.main.sync {
print("sync")
}
print("Finish")
}
NEVER call the sync function on the main queue
If you call the sync function on the main queue it will block the queue as well as the queue will be waiting for the task to be completed but the task will never be finished since it will not be even able to start due to the queue is already blocked. It is called deadlock.
Two (or sometimes more) items — in most cases, threads — are said to be deadlocked if they all get stuck waiting for each other to complete or perform another action. The first can’t finish because it’s waiting for the second to finish. But the second can’t finish because it’s waiting for the first to finish.
You need to be careful though. Imagine if you call sync and target the current queue you’re already running on. This will result in a deadlock situation.
Use sync to keep track of your work with dispatch barriers, or when you need to wait for the operation to finish before you can use the data processed by the closure.
When to use sync?
When we need to wait until the task is finished. F.e. when we are making sure that some function/method is not double called. F.e. we have synchronization and trying to prevent it to be double called until it's completely finished.
When you need to wait for something done on a DIFFERENT queue and only then continue working on your current queue
Synchronous vs. Asynchronous
With GCD, you can dispatch a task either synchronously or asynchronously.
A synchronous function returns control to the caller after the task is completed.
An asynchronous function returns immediately, ordering the task to be done but not waiting for it. Thus, an asynchronous function does not block the current thread of execution from proceeding on to the next function.
#sankalap, Dispatch.main is a serial queue which has single thread to execute all the operations. If we call "sync" on this queue it will block all other operations currently running on the thread and try to execute the code block inside sync whatever you have written. This results in "deadlock".
As per Apple documentation on executing dispatch_sync on a queue you're currently on will crash your code:
Calling this function and targeting the current queue results in
deadlock.
Because the current queue is the main queue, when you continue to call sync on the main queue, the system will understand that current main queue must wait some code complete in current queue, but no code at current queue (main queue), so you wait forever:
Apple document: Calling this function and targeting the current queue results in deadlock.
I have a list of files i need to upload to my server.
I want to upload each file only if the file before it uploaded successfully.
I'm looking for an elegant way to implement this.
For example using coroutines like feature.
So is there a feature like coroutines in swift?
Is there any other elegant way to implement this?
Thanks
You could use an OperationQueue. Create one like this:
lazy var queue: OperationQueue = {
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
return queue
}()
and then add an operation to it like this:
self.queue.addOperation {
// The code you want run in the background
}
Having set the maxConcurrentOperationCount to 1 it operates as a serial queue not running the next task until the current one has finished.
That's the most basic functionality but there are all kinds of more advanced things you can do so check out the documentation OperationQueue
Why not create a List of files and on the completion handler of one upload just check if the list is not empty and kick off the next one? Rather than a complicated coroutines setup I think it can be simpler by just maintaining an upload list/queue.
You can create a serial queue for that, using Grand Central Dispatch. Compared to OperationQueue suggested in on of the answers given here it has the advantage of saving quite an amount of overhead. Please see this post for details on that.
This creates the serial queue:
let serialQueue = DispatchQueue(label: "someQueueIdentifier", qos: .background)
Choose the quality of service parameter according to your needs.
Then, you could have a loop, for example, from which you place your background jobs into this queue:
while <condition> {
serialQueue.async {
// do background job
}
}
A serial queue will run one job at a time and the whole queue will be executed asynchronously in the background.
I want to know As we all know how asynchronous task are necessary for concurrency but Wanted to know why we need the synchronous tasks. while we can achieve the same with the normal usage of function.
Thanks & regards
Rohit
When you calls something synchronously, it means that 'the thread that initiated that operation will wait for the task to finish before
continuing'. Asynchronous means that it will not wait for finish the task.
synchronous calls stops your current action and returns when the call returned. with asynchronous calls you can continue.
synchronous is the opposite of asynchronous code, and therefore is ordinary code.
At the end, if asynchronous is totally out of scope then you will not emphasize the word synchronous.
It helps to synchronise threads, as the name suggests.
consider a typical usage of GCD async and sync (pseudo)
async background_thread {
//1 call webservice or other long task that would block the main thread
sync main_thread {
//2 update UI with results from 1
}
//3 do something else that relies on 2
}
now if 2 was in an async and you needed to do something at 3 that relies on the updates at 2 to have happened, then you are not guaranteed (and most likely wont) get the behaviour you are expecting. instead, you use a sync to make sure that the task is completed before continuing the execution in the background thread.
If you are asking now, why not just take out the sync/async around 2 so it executes in order anyway? the problem is, the UI must not be updated on a background thread otherwise the behaviour is undefined (which usually means the UI lags a lot). So in essence what happens is the background thread waits at 2's sync until the main thread gets round to executing that block, then it will continue with the rest of the execution on the background thread.
If you were dealing with a task that doesnt require the main thread (or some other thread) to execute properly, then yes you may as well take out the sync at 2.
This is just one example of how a sync is useful, there are others if you are doing advanced threading in your app.
Hope this helps
Typically it's because you want to do an operation on a specific different thread but you need the result of that operation. You cannot do the operation asynchronously because your code will proceed before the operation on the other thread completes.
Apple has a very nice example:
func asset() -> AVAsset? {
var theAsset : AVAsset!
self.assetQueue.sync {
theAsset = self.getAssetInternal().copy() as! AVAsset
}
return theAsset
}
Any thread might call the asset method; but to avoid problems with shared data, we require that only functions that are executed from a particular queue (self.assetQueue) may touch an AVAsset, so when we call getAssetInternal we do it on self.assetQueue. But we also need the result returned by our call to getAssetInternal; hence the call to sync rather than async.