要清楚:我主要是嵌入的东西,即它是C和微控制器中的某种实时内核;但实际上这个问题应该是平台无关的。 Mutexes and Semaphores Demystified,以及本related answer on StackOverflow:计数信号量的使用案例
我由迈克尔·巴尔读好文章。我清楚地明白什么是二进制信号量,什么是互斥量。那很棒。
但说实话,我从来不知道,还是不能懂,还有什么所谓的计数信号量(即,最大信号计数> 1)可以。我应该在什么情况下使用它?很久以前,在我读过迈克尔巴尔的前述文章之前,我已经告诉过类似于“”的东西,你可以在有的时候使用它,比如有一定数量的床的旅馆房间。是信号量的最大计数,就像该房间的一些键号“。
这可能听起来好听,但实际上我从来没有在我的编程实践中有过这样的情况(和无法想象任何)和迈克尔·巴尔说,这种做法是错误的,他似乎是正确的。
然后,我读过的文章后,我认为当我有,说出来可能会被使用,某种FIFO缓存。假设缓冲区的容量是10个元素,我们有两个任务:A(生产者)和B(消费者)。然后:
- 信号量的最大数应该设置为10;
- 当A希望将数据放入缓冲区,它
signal
S中的信号。 - 当B想要从缓冲区获取数据时,它是
wait
的信号量。
好,但它不工作:
- 如果A试图把新的数据到FIFO,但没有房呢?它如何等待这个地方:它应该在拨出新数据之前拨打
signal
(并且signal
然后应该能够等到最大计数为<最大计数)?如果是这样,信号量将在数据实际存入FIFO之前发出,这是错误的。 - 信号量不足以实现正确的同步:FIFO本身也需要同步。然后,它产生了经典的TOCTTOU问题:有一段时间信号量已经被发送或等待,但是FIFO尚未被修改。
那么,我应该什么时候使用那个野兽,计数信号量呢?
好吧,从生产者P1完成等待“可用”并锁定互斥锁的那一刻起,所以,可能有其他生产者P2中断了这个序列(并首先锁定了互斥体)。然后,P1锁定互斥锁,但队列已满,P1必须解锁互斥锁并再次等待“可用”。这真的很好吗?哇,只有一个数据队列的三个对象。我使用的实时内核(TNeoKernel:https://bitbucket.org/dfrank/tneokernel)提供了提供原子等待和放置数据以及原子等待和获取数据操作的数据队列。 – 2014-10-07 08:56:52
好吧,从生产者P1完成等待“可用”并锁定互斥锁的那一刻起,因此,在这种情况下,可能有其他生产者P2中断了该序列(并且先锁定互斥体)',因为这两个线程都从'可用'信号量获得了单元,所以在该队列中必须有两个空闲空间,所以两者线程可以推送他们的对象而不会溢出队列。您建议的实时内核 - 它允许与任意数量的生产者/消费者进行阻塞,有界的队列? – 2014-10-08 02:32:37
此外,你可以用'无锁'队列替换'简单队列和互斥'。只要无锁队列类对于多个生产者和消费者是无条件安全的。 – 2014-10-08 02:37:43