我会尽力解决混乱。我将按照传统定义的方式解释这些概念。问题是人们开始混淆许多这些概念的含义,由此产生了很多混乱。
每当我们有一段代码修改了在不同进程或线程之间共享的一些内存(比如一个变量)时,我们就有了一个临界区。如果我们不注意正确同步这段代码,那么我们就会得到错误。临界区的一个示例是生产者将元素添加到某种共享容器中。
同步关键部分的一种方法是强制互斥。互斥意味着一次只有一个进程或线程可以执行临界区并获得对共享内存的访问权限。请注意,互斥本身并不是一种机制,它是我们可以通过不同方式强制执行的原则。有些人将锁和二进制信号量称为互斥体,但这会以一种会导致混淆的方式混合这些概念。
二进制信号量是一种强制互斥的方法。每当一个进程想要访问互斥体时,它都可以获取信号量。如果此时有另一个进程持有该信号量,则此操作将阻塞。因此,我们相互排斥。一旦一个进程使用互斥锁完成,我们就会释放信号量,让其他进程进入互斥锁。通过这种方式,我们可以实现与二进制信号量的互斥,但这绝不是二进制信号量唯一可能的应用。
信号量非常适合生产者-消费者问题,因为它们可以采用任意自然数,而不仅仅是二进制信号量的 0 和 1。这在同步生产者-消费者问题时非常有用,因为您可以让信号量的值包含可用元素的数量。如果元素的数量下降到零,那么信号量操作将自动阻塞。
我意识到对生产者-消费者问题的解释有点简短,我鼓励您查看使用信号量的解决方案,并将这些解决方案与使用其他同步结构(如监视器或消息传递)的其他解决方案进行比较。我发现它非常有启发性。