dispatch_barrier,dispatch_barrier_sync总是死锁

Given the following snippet of code:

#import

@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

The purpose of this test is to see if I can use a dispatch_barrier to manage a read/write lock. In this test, both the reader and writer are synchronous. The test seems to work fine when I make the barrier asynchronous, however I would like to avoid asynchronous behavior because this implementation is non-trivial.

I'm trying to understand why the write method is deadlocking. According to the GCD docs:

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.

I'm confused by what is meant by "currently executing blocks".

My interpretation is this scenario where a bunch of reads (x) get submitted, then a write (y), then more reads (z):

(x) executes

(y) waits until (x) are done

(y) blocks (z) from executing

(x) completes

(y) executes

(y) completes

(z) executes

(z) completes

解决方案

OK, after actual testing it: your code does not block - in theory.

However - in practice - it may.

What you are experiencing is a situation where all available system threads are exhausted. In order to proceed, your code would require GCD to acquire a new thread - but non is available anymore - and thus, it deadlocks.

In order to avoid such situation, you need to analyse your code where it spawns new threads in an unbound manner. This may occur with concurrent queues, where the block will block or takes too long to finish AND a high number of blocks are submitted in high frequency to that concurrent queue.

For example, if you insert a small delay:

for(int i = 0; i < 400; i++) {

usleep(1000);

dispatch_async(_workQueue, ^{

if(arc4random() % 4 == 0) {

[self write];

} else {

[self read];

}

});

}

the code may run until it finishes regularly. This of course is just to demonstrate the issue - not to fix your problem.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值