当前位置: 首页 > 工具软件 > Queue for iOS > 使用案例 >

iOS学习笔记5-GCDAsyncUdpSocket中的dispatch_queue_set_specific

鲁浩言
2023-12-01

用到GCDAsyncUdpSocket开源库的时候,发现了这个函数:
dispatch_queue_set_specific,于是做下笔记:

可重入的概念

首先,可重入的概念有点类似递归,一个函数,如果能够并行进入该函数且不出现问题,则可为可重入,而GCD是一个对共享资源的访问进行串行化的队列,所以是不可重入的,需要寻找一些技巧去绕开这个限制;

GCD可重入方法(2种方法):

1.dispatch_get_current_queue,但是这种方法已经不被苹果推荐了;
具体参考:被废弃的dispatch_get_current_queue
2.利用dispatch_queue_set_specific
首先参考被废弃的dispatch_get_current_queue中的一段代码:

dispatch_queue_t queueA = dispatch_queue_create("com.yiyaaixuexi.queueA", NULL);  
   dispatch_queue_t queueB = dispatch_queue_create("com.yiyaaixuexi.queueB", NULL);  
   dispatch_set_target_queue(queueB, queueA);  

   static int specificKey;  
   CFStringRef specificValue = CFSTR("queueA");  
   dispatch_queue_set_specific(queueA,  
                               &specificKey,  
                               (void*)specificValue,  
                               (dispatch_function_t)CFRelease);  

   dispatch_sync(queueB, ^{  
       dispatch_block_t block = ^{  
               //do something  
       };  
       CFStringRef retrievedValue = dispatch_get_specific(&specificKey);  
       if (retrievedValue) {  
           block();  
       } else {  
           dispatch_sync(queueA, block);  
       }  
   });  

而在开源库GCDAsyncUdpSocket中,也使用了类似的方法:

        // The dispatch_queue_set_specific() and dispatch_get_specific() functions take a "void *key" parameter.
        // From the documentation:
        //
        // > Keys are only compared as pointers and are never dereferenced.
        // > Thus, you can use a pointer to a static variable for a specific subsystem or
        // > any other value that allows you to identify the value uniquely.
        //
        // We're just going to use the memory address of an ivar.
        // Specifically an ivar that is explicitly named for our purpose to make the code more readable.
        //
        // However, it feels tedious (and less readable) to include the "&" all the time:
        // dispatch_get_specific(&IsOnSocketQueueOrTargetQueueKey)
        //
        // So we're going to make it so it doesn't matter if we use the '&' or not,
        // by assigning the value of the ivar to the address of the ivar.
        // Thus: IsOnSocketQueueOrTargetQueueKey == &IsOnSocketQueueOrTargetQueueKey;

        IsOnSocketQueueOrTargetQueueKey = &IsOnSocketQueueOrTargetQueueKey;//这里用地址等于地址的地址,英文有解释的

        void *nonNullUnusedPointer = (__bridge void *)self;
        dispatch_queue_set_specific(socketQueue, IsOnSocketQueueOrTargetQueueKey, nonNullUnusedPointer, NULL);
        //GCD本身是不可重入的,当设置了这一条的时候,根据IsOnSocketQueueOrTargetQueueKey就可以在下面进行相关操作了。

而在接下来的代码中使用如下:

    if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
        block();
    else
        dispatch_async(socketQueue, block);

block()是块代码;
通过以上代码就能够让GCDAsyncUdpSocket实现可重入,这应该也能够解释我发送或者接收几乎是同时的缘故了。

 类似资料: