Multithreading 具有互斥和信号量的进程间同步

Multithreading 具有互斥和信号量的进程间同步,multithreading,mutex,semaphore,Multithreading,Mutex,Semaphore,我正在自学操作系统。Tanenbaum在他的《现代操作系统》一书中陈述了一个例子,他解释了三个信号量(其中一个是互斥)如何协调生产者-消费者进程对。我很难掌握它。谁能解释一下这是如何实现的。任何帮助都将不胜感激。谢谢 #define N 1 00 typedef int semaphore; semaphore mutex = 1 ; semaphore empty = N; semaphore full = 0; void producer(vo

我正在自学操作系统。Tanenbaum在他的《现代操作系统》一书中陈述了一个例子,他解释了三个信号量(其中一个是互斥)如何协调生产者-消费者进程对。我很难掌握它。谁能解释一下这是如何实现的。任何帮助都将不胜感激。谢谢

    #define N 1 00
    typedef int semaphore;
    semaphore mutex = 1 ;
    semaphore empty = N;
    semaphore full = 0;
    void producer(void)
    {

    int item;
    while (TRUE) {
    item = produce_item( );
    down( &empty);
    down( &mutex);
    inserUtem(item);
    up(&mutex);
    up(&full);
}

    void consumer(void)
    {

    int item;
    while (TRUE) {
    down(&full);
    down( &mutex);
    item = remove_ item( );
    up(&mutex);
    up(&empty);
    consume_item(item);

}
(互斥)信号量初始化为1。只有一个线程可以获得这个单元,所有其他线程都被阻塞。它的唯一目的是防止任何类型的多个线程访问队列&从而确保典型的队列实现是线程安全的

一个信号量(full)初始化为零,并统计队列中的项目数

一个信号量(空)初始化为队列长度,并统计队列中的可用空间数

真的是这样。要推送对象,首先等待(空)以确保有可用空间,然后等待(互斥)以访问队列,推送对象(是的,总是有可用空间-无需检查队列计数),发出(互斥)信号以解锁队列,最后发出(满)信号,以便任何正在等待的使用者线程,或者稍后出现,可以获取表示队列中对象的单元

要弹出对象,首先等待(完全)以确保队列中有对象可用,然后等待(互斥)以访问队列,弹出对象(是的,队列中始终有对象-无需检查队列计数),发出信号(互斥)以解锁队列,最后发信号(空)因此,任何正在等待或稍后将出现的生产者线程都可以获得一个表示队列中可用空间的单元


这是计算机科学101之类的东西——一个绝对经典的生产者-消费者阻塞队列。

噢——忘记添加了——如果你的操作系统“支持”虚假唤醒,你可能需要添加一大堆while循环、额外锁定和额外测试。幸运的是,只有一种流行的操作系统支持虚假唤醒:)是Windows吗?还有一点需要澄清。。是否可以使用正确处理的堆栈指针(即有条件的堆栈指针),而不是使用满的和空的堆栈指针?“这是Windows吗?”-不,这是另一个有不会飞的鸟的堆栈指针。不知道你说的堆栈指针是什么意思。生产者-消费者队列的其他实现依赖于其他同步原语,例如condvar。通常首先教授基于信号量的队列,因为信号量在所有操作系统上都可用,并且很容易确定这样的队列如何工作以及如何安全。谢谢。。我的意思是我们可以跟踪堆栈指针。。如果它是0,消费者可以等待,或者如果它的大小,生产者可以等待。会是一样的吗?谢谢哦,这堆数据。我通常使用FIFO队列,但对于某些用途,堆栈是可以使用的。跟踪堆栈指针(或队列计数)本身不足以进行正确的操作,因为对计数进行了非原子检查,并因此采取了操作。信号量之所以有效,是因为信号和等待是原子的——线程可以调用wait(),如果计数为零,则会被阻塞,而无需对计数进行任何显式和单独的检查。类似地,一个信号将设置一个等待线程就绪,或者,如果没有等待线程,则在一个原子调用中增加计数。