3

这个 Apple 的关于 的文档中NSCondition, 的用法NSCondition应该是:

标题 1:

[cocoaCondition lock];
while (timeToDoWork <= 0)
    [cocoaCondition wait];
timeToDoWork--;
// Do real work here.
[cocoaCondition unlock];

线程 2:

[cocoaCondition lock];
timeToDoWork++;
[cocoaCondition signal];
[cocoaCondition unlock];

方法的文档signalNSConditon

您可以使用此方法唤醒一个正在等待条件的线程。您可以多次调用此方法来唤醒多个线程。如果没有线程在等待条件,则此方法不执行任何操作。为了避免竞争条件,你应该只在接收者被锁定时调用这个方法

我的问题是:

我不希望Thread 2在任何情况下都被阻塞,所以我删除了Thread 2lock中的andunlock调用。也就是说,线程 2可以放任意多的工作,线程 1会一个一个地完成工作,如果没有更多工作,它会等待(阻塞)。这也是生产者-消费者模式,但生产者从未被阻塞。

但是根据 Apple 的文档,这种方式是不正确的 那么这种模式可能会出现什么问题呢?谢谢。

4

1 回答 1

2

当多个线程访问共享数据时,锁定失败是一个严重的问题。在 Apple 代码的示例中,如果线程 2 没有锁定条件对象,那么它可以timeToDoWork在线程 1 递减它的同时递增。这可能导致其中一项操作的结果丢失。例如:

线程 1 读取 的当前值timeToDoWork,获取 1
线程 2 读取 的当前值timeToDoWork,获取 1
线程 2 计算递增值 ( timeToDoWork+1),获取 2
线程 1 计算递减值 ( timeToDoWork-1),获取 0
线程 2 写入的新值timeToDoWork,存储 2
线程 1 写入 的新值timeToDoWork,存储 0

timeToDoWork从 1 开始,递增和递减,所以它应该以 1 结束,但它实际上以 0 结束。通过重新排列步骤,它可能以 2 结束。据推测, 的值timeToDoWork代表了一些真实而重要的东西。弄错可能会搞砸程序。

如果你的两个线程正在做一些简单的事情,比如递增和递减一个数字,它们可以通过使用原子操作函数(例如OSAtomicIncrement32Barrier()和)在没有锁的情况下完成OSAtomicDecrement32Barrier()。但是,如果共享数据比这更复杂(并且可能在任何不平凡的情况下),那么他们确实需要使用条件锁等同步机制。

于 2015-01-16T05:17:12.363 回答