# 46、不要使用dispatch\_get\_current\_queue

```objectivec
- (NSString *)name {
  __block NSString *localName;
  // 如果调用方法的队列恰好使_syncQueue，则会死锁 (同步线程里加同步事件)
  dispatch_sync(_syncQueue, ^{ 
    localName = _name;
  });
  return localName;
}
```

```objectivec
dispatch_queue_t queueA = dispatch_queue_create("com.mo.queueA", NULL);
dispatch_queue_t queueB = dispatch_queue_create("com.mo.queueB", NULL);
dispatch_sync(queueA, ^{
  dispatch_sync(queueB, ^{
    dispatch_block_t block ^{ /* ... */ };
    if (dispatch_get_current_queue() == queueA) { // dispatch_get_current_queue 返回的是queueB
      block();
    } else {
      dispatch_sync(queueA, block); // 所以还是会进入死锁
    }
  });
});
```

​ 由于队列间有层级关系，所以“检查当前队列是否为执行同步派发所用的队列”这种办法，并不总是凑效。

​ 在这种情况下，正确的做法是：不要把存取方法做成可重入的，而是应该确保同步操作所有的队列，绝不会访问属性，也就是绝对不会调用`name`方法。这种队列只应该用来同步属性。由于派发队列是一种极为轻量的机制，所以不妨为每个每项属性创建专用的同步队列。

​ GCD提供了一个功能，设定“队列特有数据”，可以把任意数据以键值对的形式关联到队列里。最重要的是，若在当前层级获取不到关联数据时，系统会沿着层级体系向上查找，直到 找到数据 / 到根队列 为止。

```
dispatch_queue_t queueA = dispatch_queue_create("com.mo.queueA", NULL);
dispatch_queue_t queueB = dispatch_queue_create("com.mo.queueB", NULL);
dispatch_set_target_queue(queueB, queueA); // B嵌套在A里
static int kQueueSpecific;
CFStringRef queueSpecificValue = CFSTR("queueA");
// 为queueA设置“队列特定值”
dispatch_queue_set_specific(queueA, // 待设置数据的队列
                            &kQueueSpecific, // key
                            (void *)queueSpecificValue, // value 
                            (dispatch_funcion_t)CFRelease); // 析构方法
dispatch_sync(queueB, ^{
  dispatch_block_t block = ^{
    NSLog(@"No deadlock!");
  };
  CFStringRef retrievedValue = dispatch_get_specific(&kQueueSpecific); // 获取队列特定值
  if (retrievedValue) { // 在A队列里
    block();
  } else {
    dispatch_sync(queueA, block);
  }
});
```

要点：

* `dispatch_get_current_queue`函数的行为常常与开发者所预期的不同。此函数已经废弃，只应做调试之用
* 由于派发队列是按层级来组织的，所以无法单用某个队列对象来描述“当前队列”这一概念
* `Dispatch_get_current_queue`函数用于解决由不可重入的代码所引发的死锁，然而能用此函数解决的问题，通常该用“队列特定数据”来解决
