GCD sync serial main_queue [duplicate] - ios

This question already has answers here:
Why dispatch_sync( ) call on main queue is blocking the main queue?
(5 answers)
dispatch_sync() always execute block in main thread
(3 answers)
Closed 6 years ago.
-(void)test1{
dispatch_queue_t queue = dispatch_get_main_queue();
NSLog(#"start");
dispatch_sync(queue, ^{
NSLog(#"%#",[NSThread currentThread]);
});
}
-(void)test2{
dispatch_queue_t queue = dispatch_queue_create("com.yaoye.serial", DISPATCH_QUEUE_SERIAL);
NSLog(#"start");
dispatch_sync(queue, ^{
NSLog(#"%#",[NSThread currentThread]);
});
}
Test1 and test2 are executed in the main thread
Test1 example:
the main thread is blocked waiting for synchronization function, block into the main thread of the runloop cannot be executed, lead to deadlock.
Test2 example:
the main thread waiting for synchronization function is blocked,block into the main thread of the runloop, but no deadlock.<2016-03-14 13:55:06.730 GCD[54320:12111593] <NSThread: 0x7fef4ac08810>{number = 1, name = main}>
queation:
Why not is test2 deadlock?

because test1 uses the same main queue, whereas test2 uses a different queue

Related

How does dispatch_barrier_async interact with the target queue?

Given the creation of queue2 with target of queue1 (queue2 = dispatch_queue_create_with_target(name, attr, queue1))...
If both queues are concurrent, does dispatch_barrier_async on queue2 only wait on queue2 to be empty, or does it also wait for the target queue? When both queues have respective barrier blocks queued, does queue2's barrier block take priority?
A barrier on queue does not affect its target queue.
This is most easily demonstrated empirically. For example:
- (void)experiment {
dispatch_queue_t queue1 = dispatch_queue_create("1", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t queue2 = dispatch_queue_create_with_target("2", DISPATCH_QUEUE_CONCURRENT, queue1);
dispatch_async(queue1, ^{
[self taskOnQueue:1 taskNumber:1 color:1];
});
dispatch_async(queue2, ^{
[self taskOnQueue:2 taskNumber:2 color:0];
});
dispatch_barrier_async(queue2, ^{
[self taskOnQueue:2 taskNumber:3 color:0];
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
dispatch_async(queue2, ^{
[self taskOnQueue:2 taskNumber:4 color:0];
});
dispatch_async(queue1, ^{
[self taskOnQueue:1 taskNumber:5 color:1];
});
});
}
Tasks 1-3 are immediately dispatched, and tasks 4 and 5 are dispatched 0.5 seconds later. Task 3 is using a barrier. Tasks 1 and 5 are on queue1, and tasks 2-4 are on queue2. All tasks take one second each.
That results in the following. (I manually highlighted those task numbers to make this more clear.)
You can see that task #5 on queue 1 starts as soon as it's queued, even though (a) it was the last task queued, and (b) queue 2 has a barrier on task #3. The second queue respects the barrier on task 3, though.
FYI, this these are the utility methods that generate those points of interest ranges:
- (void)taskOnQueue:(uint32_t)code taskNumber:(uint32_t)arg1 color:(uint32_t)arg4 {
[self pointOfInterest:code arg1:arg1 color:arg4 block:^{
[NSThread sleepForTimeInterval:1];
}];
}
- (void)pointOfInterest:(uint32_t)code arg1:(uint32_t)arg1 color:(uint32_t)arg4 block:(void (^)(void))block {
kdebug_signpost_start(code, arg1, 0, 0, arg4);
block();
kdebug_signpost_end(code, arg1, 0, 0, arg4);
}
NB: The converse is a completely different issue. Queues will be affected if their target queue has a barrier. If the target queue is blocked (for example, if you change task 3 to run with a barrier on the target queue, queue1, instead), then tasks on the second queue will wait for its target queue to free up:
- (void)experiment2 {
dispatch_queue_t queue1 = dispatch_queue_create("1", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t queue2 = dispatch_queue_create_with_target("2", DISPATCH_QUEUE_CONCURRENT, queue1);
dispatch_async(queue1, ^{
[self taskOnQueue:1 taskNumber:1 color:1];
});
dispatch_async(queue2, ^{
[self taskOnQueue:2 taskNumber:2 color:0];
});
dispatch_barrier_async(queue1, ^{ // changed to queue 1
[self taskOnQueue:1 taskNumber:3 color:1];
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
dispatch_async(queue2, ^{
[self taskOnQueue:2 taskNumber:4 color:0];
});
dispatch_async(queue1, ^{
[self taskOnQueue:1 taskNumber:5 color:1];
});
});
}
That will result in:
Here, task 3 was dispatched with a barrier (where that first Ⓢ signpost is), and not only did it not start until task 1 was done on the target queue, but task 4 (running on the second queue) on the second queue (dispatched where that second Ⓢ signpost is) waited for that barrier on its queue's target queue, too, just like task 5 did.

Why asynchronous parallel queues are run at the end

I think "end" will be print in for loop, but this is wrong, can you tell me why. This is code:
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
for (NSUInteger i = 0; i < 1000; i++) {
dispatch_async(queue, ^{
NSLog(#"i:%lu", (unsigned long)i);
});
}
dispatch_async(queue, ^{
NSLog(#"end:%#", [NSThread currentThread]);
});
Result:
2018-03-22 19:26:33.812371+0800 MyIOSNote[96704:912772] i:990
2018-03-22 19:26:33.812671+0800 MyIOSNote[96704:912801] i:991
2018-03-22 19:26:33.812935+0800 MyIOSNote[96704:912662] i:992
2018-03-22 19:26:33.813295+0800 MyIOSNote[96704:912802] i:993
2018-03-22 19:26:33.813552+0800 MyIOSNote[96704:912766] i:994
2018-03-22 19:26:33.813856+0800 MyIOSNote[96704:912778] i:995
2018-03-22 19:26:33.814299+0800 MyIOSNote[96704:912803] i:996
2018-03-22 19:26:33.814648+0800 MyIOSNote[96704:912779] i:997
2018-03-22 19:26:33.814930+0800 MyIOSNote[96704:912759] i:998
2018-03-22 19:26:33.815361+0800 MyIOSNote[96704:912804] i:999
2018-03-22 19:26:33.815799+0800 MyIOSNote[96704:912805] end:<NSThread: 0x60400027e200>{number = 3, name = (null)}
Look at the order of execution. You first enqueue 1000 blocks to print a number. Then you enqueue the block to print "end". All of those blocks are enqueued to run asynchronously on the same concurrent background queue. All 1001 calls to dispatch_async are being done in order, one at a time, on whatever thread this code is being run on which is from a different queue all of the enqueued blocks will be run on.
The concurrent queue will pop each block in the order it was enqueued and run it. Since it is a concurrent queue and since each is to be run asynchronously, in theory, some of them could be a bit out of order. But in general, the output will appear in the same order because each block does exactly the same thing - a simple NSLog statement.
But the short answer is that "end" is printed last because it was enqueued last, after all of the other blocks have been enqueued.
What may help is to log each call as it is enqueued:
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
for (NSUInteger i = 0; i < 1000; i++) {
NSLog(#"enqueue i: %lu", (unsigned long)i);
dispatch_async(queue, ^{
NSLog(#"run i: %lu", (unsigned long)i);
});
}
NSLog(#"enqueue end");
dispatch_async(queue, ^{
NSLog(#"run end: %#", [NSThread currentThread]);
});
For loop code runs in main Queue (Serial) so the for loop ends then the end statement is printed , if you wrapped the for loop inside the async like this
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
for (NSUInteger i = 0; i < 1000; i++) {
NSLog(#"i:%lu", (unsigned long)i);
}
});
dispatch_async(queue, ^{
NSLog(#"end:%#", [NSThread currentThread]);
});
you will get this
To combine both of the previous answers, the reason you see end printed last is because you enqueue serially, but each block executes very quickly. By the time you enqueue the log of end, all the other blocks have already executed.

Why Dispatch_group_notify works different in different environment?

The first situation is that I create a Command Line Tool Application,and run this code.
NSLog(#"Main:%#", [NSThread currentThread]);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
NSLog(#"Task1:%#", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(#"Task2:%#", [NSThread currentThread]);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(#"Finish:%#", [NSThread currentThread]);
});
The log in terminal is
Main:<NSThread: 0x1028033b0>{number = 1, name = main}
Task2:<NSThread: 0x10040f0f0>{number = 2, name = (null)}
Task1:<NSThread: 0x1006008d0>{number = 3, name = (null)}
If I want to show last log in queue and replace the main queue
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(#"Finish:%#", [NSThread currentThread]);
});
with queue
dispatch_group_notify(group, queue, ^{
NSLog(#"Finish:%#", [NSThread currentThread]);
});
The terminal print the last log.But why it can't revoke in Main queue?
When i copy this code to simple iOS Application.All works well:
Main:<NSThread: 0x600000070ac0>{number = 1, name = main}
Task2:<NSThread: 0x6000002633c0>{number = 3, name = (null)}
Task1:<NSThread: 0x600000263480>{number = 4, name = (null)}
MainFinish:<NSThread: 0x600000070ac0>{number = 1, name = main}
And I try to add sleep(1) over Task1 in 'Command Tool Line', but it seems block the queue and only print log:Task2.... But this all works well in simple iOS Application.
Why lead to these different?
image here
Unlike other queues that active on created,you should call dispatch_main() method to execute blocks submitted to main thread
image here
The reason for the same code runs well in iOS Application is that the application start a default runloop which execute the task submitted to the main queue according to a certain rule like UI update notification.
The reference as follow:
swift-corelibs-libdispatch
Concurrency Programming Guide

Why async blocks execution blocking main thread?

I have an app that uses AFNetworking for sending requests and after it finished downloading, it calls block where I create data models from JSON. During model initialization, there is async image loading with the following code
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *urlData = [NSData dataWithContentsOfURL:downloadURL];
}
I know that dataWithContentsOfURL: is synchronous, and in accordance with https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSData_Class/#//apple_ref/occ/clm/NSData/dataWithContentsOfURL:
... this method can block the current thread for tens of seconds on a slow
network...
But as it's executing asynchronously in other thread, it shouldn't block main thread. After some investigating, I found that starting from URLSession:task:didCompleteWithError: method that is placed inside of AFURLSessionManager.m has the following blocks hierarchy
URLSession:task:didCompleteWithError: //1
|
dispatch_async(url_session_manager_processing_queue(), ^{ //2
//url_session_manager_processing_queue() - this is the default queue
|
dispatch_group_async(url_session_manager_completion_group(), dispatch_get_main_queue(), ^{ //3
|
//Inside of my callback
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //4
|
NSData *urlData = [NSData dataWithContentsOfURL:downloadURL];
If I set AFHTTPSessionManager's completionQueue property:
_sharedClient.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
Then dispatch_group_sync ... //3 using Default queue, not main and main thread is not blocked. Can someone explain why without setting completionQueue property my main thread is blocked? (Stack trace showing semaphore_wait_trap in main thread)

queuering GCD with 2 blocks

I want create queue in that first block will run in background, then it finished I want run second block in main thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
// block 1
dispatch_async(dispatch_get_main_queue(), ^{
// block 2
});
});
How to add queue here?
What you have, i.e. nested GCD calls, should work fine. It should call the main thread only when the code above the GCD call to the main thread is finished.
You can make a queue like this:
dispatch_queue_t queue = dispatch_queue_create("com.company.queue", 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
// block 1
dispatch_group_async(group, queue, ^{
printf("first block\n");
});
// block 2
dispatch_group_async(group, queue, ^{
printf("second block\n");
});
});
dispatch_group_notify(group, queue, ^{
printf("all tasks are finished!\n");
});
dispatch_async(dispatch_get_main_queue(), ^{
// your code on main thread to update UI
printf("main thread\n");
});

Resources