C++多线程——生产者消费者模型

C++多线程——生产者消费者模型


#include <iostream>
#include <string>
#include <thread>                      // 线程类头文件。
#include <mutex>                      // 互斥锁类的头文件。
#include <deque>                      // deque容器的头文件。
#include <queue>                      // queue容器的头文件。
#include <condition_variable>  // 条件变量的头文件。
using namespace std;
class AA
{
    mutex m_mutex;                                    // 互斥锁。
    condition_variable m_cond;                  // 条件变量。
    // queue<string, deque<string>> m_q;   // 缓存队列,底层容器用deque。
    queue<string> m_q;   // 缓存队列,底层容器用deque。
public:
    void incache(int num)     // 生产数据,num指定数据的个数。
    {
        cout << this_thread::get_id() << " 生产者申请加锁..." << endl;
        lock_guard<mutex> lock(m_mutex);   // 申请加锁。
        cout << this_thread::get_id() << " 生产者申请加锁成功..." << endl;
        for (int ii = 0; ii < num; ii++)
        {
            static int bh = 1;           // 超女编号。
            string message = to_string(bh++) + "号turtle";    // 拼接出一个数据。
            m_q.push(message);     // 把生产出来的数据入队。
        }
        //m_cond.notify_one();     // 唤醒一个被当前条件变量阻塞的线程。
        m_cond.notify_all();     // 唤醒全部被当前条件变量阻塞的线程。
    }

    void outcache()       // 消费者线程任务函数。
    {
        while (true)
        {
            // 把互斥锁转换成unique_lock<mutex>,并申请加锁。
            cout << this_thread::get_id() << " 申请加锁..." << endl;
            unique_lock<mutex> lock(m_mutex);
            cout << this_thread::get_id() << " 申请加锁成功..." << endl;
            // 这里必须使用while循环,保证线程被虚假唤醒时,能够继续等待被唤醒
            // 虚假唤醒指的是线程虽然被唤醒,但是消息队列中没有数据,如果不使用循环
            // 那么当前线程永远都不会消耗消息队列中的数据
            while (m_q.empty())    // 如果队列空,进入循环,否则直接处理数据。必须用循环,不能用if
            {
                cout << this_thread::get_id() << " 等待被唤醒..." << endl;
                // 线程会被阻塞在这里,一旦接收到生产发出的信号,就继续向下执行
                // wait()的功能:(1)释放锁  (2)阻塞线程  
                m_cond.wait(lock);  // 等待生产者的唤醒信号。
                cout << this_thread::get_id() << " 被唤醒..." << endl;
            }
            lock.unlock();
            // 数据元素出队。
            string message = m_q.front();  m_q.pop();
            // 处理出队的数据(把数据消费掉)。
            this_thread::sleep_for(chrono::milliseconds(1));   // 假设处理数据需要1毫秒。
            cout << "线程:" << this_thread::get_id() << "," << message << endl;
        }
    }
};

int main()
{
    AA aa;

    thread t1(&AA::outcache, &aa);     // 创建消费者线程t1。
    thread t2(&AA::outcache, &aa);     // 创建消费者线程t2。
    thread t3(&AA::outcache, &aa);     // 创建消费者线程t3。

    cout << "即将开始生产第一波数据......" << endl;
    this_thread::sleep_for(chrono::seconds(5));    // 休眠5秒。
    aa.incache(3);      // 生产3个数据。


    this_thread::sleep_for(chrono::seconds(1));    // 休眠5秒。
    cout << "即将开始生产第二波数据......" << endl;
    this_thread::sleep_for(chrono::seconds(5));    // 休眠5秒。
    aa.incache(5);      // 生产5个数据。

    t1.join();   // 回收子线程的资源。
    t2.join();
    t3.join();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值