不要使用 dispatch_get_current_queue()
当然这个方法在iOS6.0就废弃了,这里主要是重温一下同步、异步以及死锁。
- - (NSString *)name
- {
- __block NSString *name;
- dispatch_sync(_syncQueue, ^{
- name = @"不服不行";
- });
- return name;
- }
上面的这种写法可能会出现死锁,假如调用获取方法的队列恰好是同步操作所在的队列。那么dispatch_sync就会一直不返回,需要等待块执行完毕。
这里就想到使用dispatch_get_current_queue来解决问题。
- - (NSString *)name
- {
- __block NSString *name;
- void (^block)() = ^{
- name = @"iOS";
- };
-
- if (dispatch_get_current_queue() == _syncQueue) {
- block();
- }else {
- dispatch_sync(_syncQueue, block);
- }
-
- return name;
- }
但是 dispatch_get_current_queue 仍然可能造成死锁
- dispatch_sync(_syncQueueA, ^{
- dispatch_sync(_syncQueueB, ^{
- void (^block)() = ^{
-
- };
- if (dispatch_get_current_queue() == _syncQueueA) {
- block();
- }else {
- dispatch_sync(_syncQueueA, block);
- }
- });
- });
dispatch_get_current_queue 由于返回的是当前队列,上面返回的是_syncQueueB。因此,针对_syncQueueA的同步派发依然会执行,所以还是会造成死锁。
其实要解决这个问题,可以使用队列特有数据 dispatch_queue_set_specific。只要去看源码就会发现 GPUImage(https://github.com/BradLarson/GPUImage) 等多数框架都是这么解决的。
GPUImage中如何做到 统一在某个队列执行 并防止死锁的
- @implementation GPUImageContext
-
- static void *openGLESContextQueueKey;
-
- - (id)init;
- {
- if (!(self = [super init]))
- {
- return nil;
- }
-
- openGLESContextQueueKey = &openGLESContextQueueKey;
- _contextQueue = dispatch_queue_create("com.sunsetlakesoftware.GPUImage.openGLESContextQueue", NULL);
-
- #if OS_OBJECT_USE_OBJC
- dispatch_queue_set_specific(_contextQueue, openGLESContextQueueKey, (__bridge void *)self, NULL);
- #endif
- shaderProgramCache = [[NSMutableDictionary alloc] init];
- shaderProgramUsageHistory = [[NSMutableArray alloc] init];
-
- return self;
- }
-
- + (void *)contextKey {
- return openGLESContextQueueKey;
- }
-
-
- // GPUImage/Output/GPUImageOutput.m
-
- void runSynchronouslyOnVideoProcessingQueue(void (^block)(void))
- {
- dispatch_queue_t videoProcessingQueue = [GPUImageContext sharedContextQueue];
- #if !OS_OBJECT_USE_OBJC
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wdeprecated-declarations"
- if (dispatch_get_current_queue() == videoProcessingQueue)
- #pragma clang diagnostic pop
- #else
- if (dispatch_get_specific([GPUImageContext contextKey]))
- #endif
- {
- block();
- }else
- {
- if(videoProcessingQueue)
- dispatch_sync(videoProcessingQueue, block);
- else
- {
- // NSLog(@"error: videoProcessingQueue should not be null");
- }
- }
- }
-
- void runAsynchronouslyOnVideoProcessingQueue(void (^block)(void))
- {
- dispatch_queue_t videoProcessingQueue = [GPUImageContext sharedContextQueue];
-
- #if !OS_OBJECT_USE_OBJC
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wdeprecated-declarations"
- if (dispatch_get_current_queue() == videoProcessingQueue)
- #pragma clang diagnostic pop
- #else
- if (dispatch_get_specific([GPUImageContext contextKey]))
- #endif
- {
- block();
- }else
- {
- dispatch_async(videoProcessingQueue, block);
- }
- }
参考: