4线程同步-生产者消费者问题

时间:2021-09-29 20:21:21

用C++11 实现生成者消费者问题,代码如下:

#include <stdio.h>

#include <mutex>
#include <condition_variable>
#include <vector>
#include <thread>
#include <list>

using namespace std;

template<class data_type>
class producer_consumer
{
private:
    mutex m_mutex;
    // 生产条件
    condition_variable m_cv_p;
    // 消费条件
    condition_variable m_cv_c;
    // 大小
    size_t m_repertory_size;
    // 数据仓库
    list<data_type> m_repertory;

public:
    producer_consumer(size_t n) : m_repertory_size(n)
    {
    }

    // 得到库存的数量
    size_t repertory_size()
    {
        lock_guard<mutex> lck(m_mutex);
        return m_repertory.size();
    }

    // 生产数据
    void producer(data_type item)
    {
        // 保证了只能一个线程在本函数内活跃,单本函数内阻塞的线程可以很多
        unique_lock<mutex> lck(m_mutex);
        // 睡眠条件: 不满足生产条件
        // 唤醒事件:解锁或者notify
        // 唤醒条件:锁是解开的和满足生产条件
        m_cv_p.wait(lck, bind([](size_t size, list<data_type> repertory) -> bool
        {
            return repertory.size() < size;
        }, m_repertory_size, m_repertory));
        m_repertory.push_back(item);
        // 此时并不能让别的线程执行,因为锁还没有释放
        m_cv_c.notify_one();
    };

    // 消费数据
    data_type consumer()
    {
        // 保证了只能一个线程在本函数内活跃,单本函数内阻塞的线程可以很多
        unique_lock<mutex> lck(m_mutex);
        // 睡眠条件: 不满足消费条件
        // 唤醒事件:解锁或者notify
        // 唤醒条件:锁是解开的和满足消费条件
        m_cv_c.wait(lck, bind([](list<data_type> li) -> bool{
            return li.size() > 0;
        }, m_repertory));
        data_type res = *m_repertory.begin();
        m_repertory.pop_front();
        // 此时并不能让别的线程执行,因为锁还没有释放
        m_cv_p.notify_one();
        return res;
    };
};

producer_consumer<int> pc(10);

// 生产者线程
void test_producer()
{
    for (int i = 0; i < 20; i++)
    {
        int data = rand();
        pc.producer(data);
        printf("生产数据:%d 仓库数量: %d \n", data,pc.repertory_size());
        this_thread::sleep_for(chrono::seconds(1));
    }
}

// 消费者线程
void test_consumer()
{
    for (int i = 0; i < 20; i++)
    {
        auto data = pc.consumer();// 消费数据();
        printf("消费数据:%d 仓库数量: %d \n", data,pc.repertory_size());
        this_thread::sleep_for(chrono::seconds(2));
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    thread t1(test_producer);
    thread t2(test_consumer);
    t1.join();
    t2.join();
    printf("结束 \n");
    
    return 0;
}