搜公众号
推荐 原创 视频 Java开发 开发工具 Python开发 Kotlin开发 Ruby开发 .NET开发 服务器运维 开放平台 架构师 大数据 云计算 人工智能 开发语言 其它开发 iOS开发 前端开发 JavaScript开发 Android开发 PHP开发 数据库
Lambda在线 > AC自动机 > 串行队列的死锁

串行队列的死锁

AC自动机 2018-12-30
举报

问题

这个死锁是会发生在 dispatch_sync 这个GCD接口调用上。

Summary

Submits a block object for execution on a dispatch queue and waits until that block completes.

1void dispatch_sync(dispatch_queue_t queuedispatch_block_t block);

Discussion

Submits a block to a dispatch queue for synchronous execution. Unlike dispatch_async, this function does not return until the block has finished. Calling this function and targeting the current queue results in deadlock.
Unlike with dispatch_async, no retain is performed on the target queue. Because calls to this function are synchronous, it "borrows" the reference of the caller. Moreover, no Block_copy is performed on the block.
As an optimization, this function invokes the block on the current thread when possible.

正如 接口文档中所说的那样: Calling this function and targeting the current queue results in deadlock 在当前线程队列中使用本接口是会导致死锁的。

这个死锁情况仅限在 DISPATCH_QUEUE_SERIAL的线程队列中。串行队列同步调用会死锁等待。

如何解决

使用串行队列可以避免加锁操作,像一些著名的三方库GCDAsyncSocket,FMDB都有这种使用场景:

GCDAsyncSocket

 1if (sq)
2{
3    NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
4                @"The given socketQueue parameter must not be a concurrent queue.");
5    NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
6                @"The given socketQueue parameter must not be a concurrent queue.");
7    NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
8                @"The given socketQueue parameter must not be a concurrent queue.");
9
10    socketQueue = sq;
11    #if !OS_OBJECT_USE_OBJC
12    dispatch_retain(sq);
13    #endif
14else {
15    socketQueue = dispatch_queue_create([GCDAsyncSocketQueueName UTF8String], NULL);
16}
1IsOnSocketQueueOrTargetQueueKey = &IsOnSocketQueueOrTargetQueueKey;        
2void *nonNullUnusedPointer = (__bridge void *)self;
3dispatch_queue_set_specific(socketQueue, IsOnSocketQueueOrTargetQueueKey, nonNullUnusedPointer, NULL);

再看一下他的sync逻辑是如何控制:

1if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) {
2    [self closeWithError:nil];
3else {
4    dispatch_sync(socketQueue, ^{
5        [self closeWithError:nil];
6    });
7}

用意就很明确了,在sync可能会导致死锁的情况下,先判断一下是否已经处于当前队列中。

还有一个不推荐的做法来自GPUImage

 1#if !OS_OBJECT_USE_OBJC
2#pragma clang diagnostic push
3#pragma clang diagnostic ignored "-Wdeprecated-declarations"
4    if (dispatch_get_current_queue() == videoProcessingQueue)
5#pragma clang diagnostic pop
6#else
7    if (dispatch_get_specific([GPUImageContext contextKey]))
8#endif
9    {
10        block();
11    }else {
12        dispatch_sync(videoProcessingQueue, block);
13    }

这里他还使用dispatch_get_current_queue()API, 但苹果的文档中已经标注为废弃API了。

This function is deprecated and will be removed in a future release.
不会在未来的版本中保证该API是否还会存在。


版权声明:本站内容全部来自于腾讯微信公众号,属第三方自助推荐收录。《串行队列的死锁》的版权归原作者「AC自动机」所有,文章言论观点不代表Lambda在线的观点, Lambda在线不承担任何法律责任。如需删除可联系QQ:516101458

文章来源: 阅读原文

相关阅读

关注AC自动机微信公众号

AC自动机微信公众号:gh_ab9dbd4593d7

AC自动机

手机扫描上方二维码即可关注AC自动机微信公众号

AC自动机最新文章

精品公众号随机推荐

下一篇 >>

14.4死锁

举报