某些设备上的`dispatch_semaphore_wait()`有问题吗?

时间:2013-10-10 21:57:21

标签: ios objective-c macos cocoa-touch cocoa

我正在使用开源软件TMCache。 它以异步方式将昂贵的数据保存到缓存中。还有一种同步方法。

它使用dispatch_semaphore_wait()等待操作结束。


Source

- (id)objectForKey:(NSString *)key
{
    if (!key)
        return nil;

    __block id objectForKey = nil;

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    [self objectForKey:key block:^(TMCache *cache, NSString *key, id object) {
        objectForKey = object;
        dispatch_semaphore_signal(semaphore);
    }];

    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

    #if !OS_OBJECT_USE_OBJC
    dispatch_release(semaphore);
    #endif

    return objectForKey;
}

这在我的机器上工作正常。在同事的机器上它没有。 该程序在dispatch_semaphore_wait()停止工作。这对我来说绝对不可复制。

上述方法在tableView:viewForTableColumn:row:
中调用 所以它在主队列中执行。

知道为什么会这样吗?我必须在另一个队列中使用该方法吗?

1 个答案:

答案 0 :(得分:6)

很可能你的线程用完了。应该释放dispatch_semaphore_wait()的dispatch_semaphore_signal(信号量)需要在新线程中执行(有关详细信息,请参阅 objectForKey:block:)。如果操作系统无法调度该新线程,那么您就会卡住,因为没有人会向您发送dispatch_semaphore_signal。

发生的频率和时间取决于计算机/设备的速度,滚动表格的速度等等。这就是您无法在计算机上重现此问题的原因。

这里的快速解决方案是通过采用相同的调度信号量方法并将超时设置为DISPATCH_TIME_NOW来保持线程数较低,因为您可能无法阻止主队列。

我宁愿改变TMCache.m的工作方式。我相信在这种情况下调度信号量方法是不合理的 - 获得代码简洁(将异步方法包装到同步对应方式中)以牺牲可靠性为代价对我来说似乎并不合适。我曾经用异步方法包装同步方法,但反之亦然。

这是修复

https://github.com/rushproject/TMCache

请注意,只修补了同步的objectForKey方法。