当有两个不同的信号和地点时,如何使用NSCondition等待

时间:2014-03-31 13:10:18

标签: ios iphone multithreading mutex nscondition

这是我在方法中所拥有的伪代码:

NSCondition condition = [[NSCondition alloc] init];
int         predicate = 0;

dispatch_sync(dispatch_get_main_queue(), ^
{
    [condition lock];   // Lock-0
});

bindBlock1ForDataReceived(^()
{
    // Not main thread here.
    // Get on main thread, because lock and unlock must be run on same thread.
    dispatch_sync(dispatch_get_main_queue(), ^
    {
        predicate = 1;
        [condition signal];
        [condition unlock]; <<<<---- "unlocked when not locked"
    });
});

bindBlock2ForNoDataAvailable(^()
{
    // Not main thread here.
    // Get on main thread, because lock and unlock must be run on same thread.
    dispatch_sync(dispatch_get_main_queue(), ^
    {
        predicate = 2;
        [condition signal];
        [condition unlock];
    });
});

[condition lock];  // Lock-1
while (predicate == 0)
{
    [condition waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:5.0]];
}
[condition unlock];

if (predicate == 2)
{
    [condition lock];  // Lock-2
    [condition waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];
    [condition unlock];
}

问题是,当第一个事件2发生,然后是事件1时,我从iOS(见上文)获得“未锁定时解锁”警告。

现在让我解释一下我要完成的任务:这是数据获取器的一部分。接收正常情况数据并执行block1:没有问题。有时,无数据块2首先被虚假执行,紧接着是block1;这是我收到NSCondition警告的时候。为了抓住这种罕见的情况,我等待2.0秒。这是发生的事情:

  • Block2表示该情况。
  • Lock-1落空。
  • predicate不再是0所以没有等待。
  • 条件再次解锁。
  • 然后我们继续查看条件if为真的(predicate == 2)语句。
  • 该方法立即获得Lock-2。 &LT;&LT;&LT;&LT; ROOT CAUSE
  • 随后该方法等待2.0秒。
  • 在这2秒内执行block1并发出信号。
  • 然后block1解锁条件&amp;该方法也解锁了。

根本原因(见上文)是方法(工人/消费者)获取锁,而数据生产者应该获取锁。我花了很多时间试图解决这个问题;我的一个想法是使用两个NSCondition,但我无法弄明白,因为事情是相互交织的。

注意:我发现警告没有出现在unlock声明中的if,这很奇怪。

谢谢你的时间!

1 个答案:

答案 0 :(得分:1)

使用

的最简单方法是使用

dispatch_group_t confirmGroup = dispatch_group_create(); // 1

if (requestContacts) {
    dispatch_group_enter(confirmGroup); // 2
    [Extractor requestAccessAddressBook:^(BOOL isComplete) {
        if (isComplete) {
            dispatch_group_leave(confirmGroup); //2
        }
    }];


}
if (requestEvent) {
    dispatch_group_enter(confirmGroup); // 3       
    [Extractor requestAccessEvents:^(BOOL isComplete) {
        if (isComplete) {
            dispatch_group_leave(confirmGroup); // 3
        }
    }];
}
if (requestPhoto) {
    dispatch_group_enter(confirmGroup); // 4
    [Extractor requestAccessPhotos:^(BOOL isComplete) {
        if (isComplete) {
            dispatch_group_leave(confirmGroup); //4
        }
    }];
}
NSLog(@"dispatch_group_wait confirmations");
dispatch_group_wait(confirmGroup, DISPATCH_TIME_FOREVER); // 5