NSCondition,如果调用信号时没有锁定怎么办?
NSCondition, what if no lock when call signal?
从this Apple's document about 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];
在the document of method signal
in NSConditon
中:
You use this method to wake up one thread that is waiting on the condition. You may call this method multiple times to wake up multiple threads. If no threads are waiting on the condition, this method does nothing. To avoid race conditions, you should invoke this method only while the receiver is locked.
我的问题是:
我不希望 线程 2 在任何情况下都被阻塞,所以我删除了 [=35= 中的 lock
和 unlock
调用]线程 2。也就是说,Thread 2想放多少工作就放多少,Thread 1会一个接一个地工作,如果没有更多的工作,它等待(阻塞)。这也是生产者消费者模式,但是生产者从来没有被阻塞过。
但是根据Apple的文档,这种方式是不正确的那么这种模式可能会出现什么问题呢?谢谢。
当多个线程访问共享数据时,无法锁定是一个严重的问题。在 Apple 代码的示例中,如果线程 2 不锁定条件对象,那么它可以在线程 1 递减它的同时递增 timeToDoWork
。这可能会导致其中一个操作的结果丢失。例如:
线程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()
)在没有锁的情况下完成。但是,如果共享数据比这更复杂(并且可能在任何非平凡的情况下),那么他们确实需要使用同步机制,例如条件锁。
从this Apple's document about 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];
在the document of method signal
in NSConditon
中:
You use this method to wake up one thread that is waiting on the condition. You may call this method multiple times to wake up multiple threads. If no threads are waiting on the condition, this method does nothing. To avoid race conditions, you should invoke this method only while the receiver is locked.
我的问题是:
我不希望 线程 2 在任何情况下都被阻塞,所以我删除了 [=35= 中的 lock
和 unlock
调用]线程 2。也就是说,Thread 2想放多少工作就放多少,Thread 1会一个接一个地工作,如果没有更多的工作,它等待(阻塞)。这也是生产者消费者模式,但是生产者从来没有被阻塞过。
但是根据Apple的文档,这种方式是不正确的那么这种模式可能会出现什么问题呢?谢谢。
当多个线程访问共享数据时,无法锁定是一个严重的问题。在 Apple 代码的示例中,如果线程 2 不锁定条件对象,那么它可以在线程 1 递减它的同时递增 timeToDoWork
。这可能会导致其中一个操作的结果丢失。例如:
线程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()
)在没有锁的情况下完成。但是,如果共享数据比这更复杂(并且可能在任何非平凡的情况下),那么他们确实需要使用同步机制,例如条件锁。