【问题标题】:classical producer consumer threading经典的生产者消费者线程
【发布时间】:2012-06-24 18:32:49
【问题描述】:

Classical producer consumer problem。当itemCount == BUFFER_SIZE amd 宕机时再次唤醒时,生产者睡觉。但是一旦itemCount 长大,生产者线程就会进入休眠状态。它怎么知道itemCount已经挂了,需要wakeup

【问题讨论】:

    标签: c++ multithreading producer-consumer


    【解决方案1】:

    在伪代码中,生产者类似于:

    void producer_thread()
    {
        while(true)
            queue.push( produce() );
    }
    

    所以考虑队列推送方法(我在这里使用了 pthreads,但同样的逻辑也适用于其他库)

    void SynchronizedQueue::push(Item const &i)
    {
        pthread_mutex_lock(&mutex);
    
        // queue is full, so wait for consumer
        while (queue.size() == BUFFER_SIZE)
            pthread_cond_wait(&condition, &mutex);
    
        // when we get here, the queue has space
        this->queue.push_back(i);
    
        // make sure we wake a sleeping consumer
        if (queue.size() == 1)
            pthread_cond_signal(&condition);
    
        pthread_mutex_unlock(&mutex);
    }
    

    以及消费者使用的pop方法:

    Item SynchronizedQueue::pop()
    {
        pthread_mutex_lock(&mutex);
    
        // wait for something to do
        while (queue.size() == 0)
            pthread_cond_wait(&condition, &mutex);
    
        // if we get here, we have some work
        Item tmp = queue.front();
    
        // make sure we wake a sleeping producer
        if (queue.size() == BUFFER_SIZE)
            pthread_cond_signal(&condition)
    
        queue.pop_front();
        pthread_mutex_unlock(&mutex);
        return tmp;
    }
    

    【讨论】:

    • 你是如何定义condition的?
    • 正如 Nawaz 所说,这是条件变量的标准用法。因此,在这段代码中,它将被声明为pthread_cond_t condition。不过,我可以使用 C++11 的 std::condition_variablestd::unique_lock 实现完全相同的逻辑;这是您链接的维基百科页面的使用监视器部分中描述的逻辑。
    【解决方案2】:

    你需要条件变量。

    条件变量的典型用法是这样的:

    //lock the mutex first!
    scoped_lock myLock(myMutex); 
    
    //wait till a condition is met
    myConditionalVariable.wait(myLock, CheckCondition);
    
    //Execute this code only if the condition is met
    

    whereCheckCondition 是一个检查条件(例如何时唤醒)的函数(或函子)。它由wait() 函数在内部虚假地 唤醒时调用,如果条件尚未满足,wait() 函数将再次休眠。在睡觉之前,wait()原子地释放了互斥锁。


    如果你的编译器支持C++11引入的std::conditional,那么你可以看看这个详细说明:

    如果您的编译器不支持它,而您使用的是 win32 线程,那么请查看:

    here 就是一个完整的例子。

    如果您使用 POSIX 线程,请查看:


    你可以在这里看到我使用win32原语实现conditional_variable

    向下滚动,先看它的实现,再看并发队列实现中的用法。

    【讨论】:

      【解决方案3】:

      它不需要知道 - 操作系统会在消费者发出信号时唤醒它。在 P-C 队列代码中,生产者将对某些 OS 同步原语进行 wait() 调用。在消费者线程腾出空间并向操作系统同步对象发出信号之前,此调用不会返回(除非您的故障操作系统“支持”虚假唤醒),此时等待的生产者线程将准备就绪,如果有可用的核心,立即运行 - wait() 调用将返回。

      传统上,P-C 队列由一个简单的非线程安全队列、一个用于保护其索引/指针的互斥体和两个信号量构成——一个初始化为 0 以计数队列中的项目,一个初始化为 [队列大小]计算空格。生产者在“emptySpace”上等待,当它收到信号时,锁定互斥体,将对象入队,锁定互斥体并发出“itemCount”信号。消费者等待“itemCount”,当它收到信号时,锁定互斥体,使对象出队,锁定互斥体并发出“emptySpace”信号。

      【讨论】:

        猜你喜欢
        • 2018-09-24
        • 2017-02-01
        • 2012-04-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-10
        • 1970-01-01
        相关资源
        最近更新 更多