gpt4 book ai didi

grand-central-dispatch - dispatch_barrier_sync 总是死锁

转载 作者:行者123 更新时间:2023-12-04 08:41:53 24 4
gpt4 key购买 nike

给定以下代码片段:

#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 方法会死锁。根据 GCD 文档:

When the barrier block reaches the front of a private concurrent queue, it is not executed immediately. Instead, the queue waits until its currently executing blocks finish executing. At that point, the queue executes the barrier block by itself. Any blocks submitted after the barrier block are not executed until the barrier block completes.

我对“当前正在执行的 block ”的含义感到困惑。

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

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

最佳答案

好的,经过实际测试:您的代码不会阻塞 - 理论上。

但是 - 在实践中 - 它可能

您遇到的是所有可用系统线程都已耗尽的情况。为了继续,您的代码需要 GCD 获取一个新线程 - 但不再可用 - 因此,它会死锁。

为了避免这种情况,您需要分析代码以未绑定(bind)方式生成新线程的位置。这可能发生在并发队列中,其中 block 将阻塞或需要很长时间才能完成,并且大量 block 以高频率提交到该并发队列。

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

for(int i = 0; i < 400; i++) {
usleep(1000);
dispatch_async(_workQueue, ^{
if(arc4random() % 4 == 0) {
[self write];
} else {
[self read];
}

});
}

代码可能会运行,直到它定期完成。这当然只是为了演示问题 - 而不是解决您的问题。

关于grand-central-dispatch - dispatch_barrier_sync 总是死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36634315/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com