首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >dispatch_barrier_sync总是死锁

dispatch_barrier_sync总是死锁
EN

Stack Overflow用户
提问于 2016-04-14 21:27:00
回答 1查看 983关注 0票数 3

给出以下代码片段:

代码语言:javascript
复制
#import <XCTest/XCTest.h>

@interface DispatchTests : XCTestCase {
    dispatch_queue_t _workQueue;
    dispatch_queue_t _readWriteQueue;
    int _value;
}
-(void)read;
-(void)write;
@end

@implementation DispatchTests

-(void)testDispatch {
    _workQueue = dispatch_queue_create("com.work", DISPATCH_QUEUE_CONCURRENT);
    _readWriteQueue = dispatch_queue_create("com.readwrite", DISPATCH_QUEUE_CONCURRENT);
    _value = 0;
    for(int i = 0; i < 100; i++) {
        dispatch_async(_workQueue, ^{
            if(arc4random() % 4 == 0) {
                [self write];
            } else {
                [self read];
            }
        });
    }
    XCTestExpectation* expectation = [self expectationWithDescription:@"dude"];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [expectation fulfill];
    });

    [self waitForExpectationsWithTimeout:6.0 handler:nil];
}

-(void)read {
    dispatch_sync(_readWriteQueue, ^{
        NSLog(@"read:%d", _value);
    });
}

-(void)write {
    dispatch_barrier_sync(_readWriteQueue, ^{
        _value++;
        NSLog(@"write:%d", _value);
    });
}

@end

这个测试的目的是看看我是否可以使用dispatch_barrier来管理读/写锁。在这个测试中,读者和作者都是同步的。当我使屏障异步的时候,测试似乎工作得很好,但是我想避免异步行为,因为这个实现是不平凡的。

我试图理解为什么write方法是死锁的。根据全球荒漠化理事会的文件:

当屏障块到达私有并发队列的前端时,它不会立即执行。相反,队列等待到当前执行的块完成执行。此时,队列自行执行屏障块。在屏障块之后提交的任何块在屏障块完成之前都不会执行。

我搞不懂“当前正在执行的块”是什么意思。

我的解释是这样的场景,其中一组读(x)被提交,然后是写(y),然后是更多的读(z):

  • (x)执行
  • (y)等待(x)完成
  • (y)阻止(z)执行
  • (x)完成
  • (y)执行
  • (y)完成
  • (z)执行
  • (z)完成
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-04-14 22:29:24

好的,在实际测试之后:您的代码不会在理论上阻塞。

然而--在实践中--它可能。

您正在经历的情况是,所有可用的系统线程都已耗尽。为了继续执行,您的代码将要求GCD获得一个新线程--但是non不再可用--因此,它会死锁。

为了避免这种情况,您需要分析您的代码,它以未绑定的方式生成新线程。这种情况可能发生在并发队列中,在这种情况下,块会阻塞或花费太长时间才能完成,并且会向该并发队列提交大量的块。

例如,如果插入一个小延迟:

代码语言:javascript
复制
for(int i = 0; i < 400; i++) {
    usleep(1000);
    dispatch_async(_workQueue, ^{
        if(arc4random() % 4 == 0) {
            [self write];
        } else {
            [self read];
        }

    });
}

代码可以运行,直到它定期完成。当然,这只是为了证明问题-而不是解决你的问题。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36634315

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档