Tim*_*ddy 3 deadlock grand-central-dispatch
给出以下代码段:
#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
Run Code Online (Sandbox Code Playgroud)
该测试的目的是查看是否可以使用a dispatch_barrier来管理读/写锁定。在此测试中,读取器和写入器都是同步的。当我使障碍异步时,该测试似乎可以正常工作,但是我想避免异步行为,因为这种实现是不平凡的。
我试图了解为什么该write方法会死锁。根据GCD文档:
当屏障块到达专用并发队列的前面时,不会立即执行。相反,队列将等待直到其当前正在执行的块完成执行。此时,队列将自己执行屏障块。在障碍块完成之前,不会执行任何在障碍块之后提交的块。
我对“当前正在执行的块”的含义感到困惑。
我的解释是这种情况:提交一堆读(x),然后写(y),然后读更多(z):
好的,在实际测试之后:理论上,您的代码不会阻塞。
但是-在实践中-它可能会。
您遇到的情况是所有可用的系统线程都用尽了。为了继续进行,您的代码将要求GCD获取一个新线程-但现在不再可用-从而导致死锁。
为了避免这种情况,您需要分析代码以非绑定方式生成新线程的地方。这可能发生在并发队列中,在该队列中,该块将阻塞或花费太长时间才能完成,并且大量块以高频率提交给该并发队列。
例如,如果插入一个小的延迟:
for(int i = 0; i < 400; i++) {
usleep(1000);
dispatch_async(_workQueue, ^{
if(arc4random() % 4 == 0) {
[self write];
} else {
[self read];
}
});
}
Run Code Online (Sandbox Code Playgroud)
该代码可能会一直运行到正常完成为止。当然,这只是为了演示问题-不能解决您的问题。
| 归档时间: |
|
| 查看次数: |
613 次 |
| 最近记录: |