C++ 11多线程编程--条件变量

条件变量->允许一个线程阻塞,直到另一个线程设置了某个条件或系统时间达到了某个指定时间。条件变量允许显示的线程间通信。
使用条件变量需要包含<condition_variable>,标准中有两种类型的条件变量。
  • std::condition_variable: 只能等待unique_lock<mutex>的条件变量。
      1 notify_once() 唤醒等待这个变量的线程之一。
      2 notify_all()     唤醒所有等待这个变量的线程。
      3 wait(unique_lock<mutex>&lk) 
  • std::condition_variable_any:可以等待任何对象的条件变量,包括自定义锁的类型
注:代码摘自 《c++高级编程》
<pre name="code" class="cpp">//logger.h
#pragma once
#include<string>
#include<thread>
#include<condition_variable>
#include<mutex>
#include<queue>
#include<fstream>
#include<iostream>
class logger
{
public:
                //Starts a background thread writing log entries to a file
                logger();
                //Gracefully shut down background thread
                virtual ~logger();
                //Add log entry to the queue
                void log(const std::string &entry);
protected:
                void processEntries();
                bool mThreadStarted;
                bool mExit;
                //Mutex and condition variable to protect when the thread starts executing its loop
                //后台线程,处理队列
                std::mutex mMutex;

                std::condition_variable mCondvar;

                //信息队列
                std::queue<std::string> mQueue;
                /*queue 的基本操作有:
                  入队,如例:q.push(x); 将x 接到队列的末端。
                  出队,如例:q.pop(); 弹出队列的第一个元素,注意,并不会返回被弹出元素的值。
                  访问队首元素,如例:q.front(),即最早被压入队列的元素。
                  访问队尾元素,如例:q.back(),即最后被压入队列的元素。
                  判断队列空,如例:q.empty(),当队列空时,返回true。*/
                std::thread mThread;

                std::mutex mMutexStarted;
                std::condition_variable mCondVarStarted;
private:
                //prevent copy construction and assignment
                logger(const logger &src);
                logger &operator =(const logger&rhs);

};

 
 
<div><pre name="code" class="cpp">//logger.cpp
#include "stdafx.h"
#include "logger.h"

//
logger::logger():mExit(false)
{
                //Start background thread
                mThread = std::thread{ &logger::processEntries,this};
                //Wait until background thread starts its processing loop
                std::unique_lock<std::mutex> lock(mMutexStarted);
                //在mThreadStarted 为true是将线程唤醒
                mCondVarStarted.wait(lock, [&]() {return mThreadStarted == true; });

}

logger::~logger()
{

                //析构时将mExit 置为 true 并唤醒线程mThread 将队列中的信息全部写到log.txt 中 并将队列清空 并终止循环 避免程序结束时 队列中仍有信息
                mExit = true;
                mCondvar.notify_all();

                //阻止调用线程。直到此实例的线程终止
                // 防止队列中还有信息时 程序退出
                mThread.join();
}

void logger::log(const std::string & entry)
{
                std::unique_lock<std::mutex> lock(mMutex);
                mQueue.push(entry);
                mCondvar.notify_all();
}

void logger::processEntries()
{
                //open file
                std::ofstream ofs("log.txt");
                if (ofs.fail())
                {
                                std::cerr << "Faild to open logfile" << std::endl;
                                return;
                }
                //Star processing loop
                //通过这个互斥体保护队列的访问
                std::unique_lock<std::mutex> lock(mMutex);

                // 将mThreadStarted 置为true 并唤醒mThread 防止后台线程还没有开始处理循环的时候 main函数剩下的代码都执行完了

                mThreadStarted = true;
                mCondVarStarted.notify_all();
                while (true)
                {
                                mCondvar.wait(lock);
                                lock.unlock();
                                while (true)
                                {
                                                lock.lock();
                                                if (mQueue.empty()) { break; }
                                                else
                                                {
                                                                //向log.txt中输出队列的首项,mQueue.front()返回队首元素
                                                                ofs << mQueue.front() << std::endl;
                                                                //出队,如例:q.pop(); 弹出队列的第一个元素,注意,并不会返回被弹出元素的值。
                                                                mQueue.pop();
                                                }
                                                lock.unlock();
                                }
                                if (mExit) break;
                }
}
/*queue 的基本操作有:
入队,如例:q.push(x); 将x 接到队列的末端。
出队,如例:q.pop(); 弹出队列的第一个元素,注意,并不会返回被弹出元素的值。
访问队首元素,如例:q.front(),即最早被压入队列的元素。
访问队尾元素,如例:q.back(),即最后被压入队列的元素。
判断队列空,  如例:q.empty(),当队列空时,返回true。*/


 

#include "stdafx.h"
#include "logger.h"
#include <sstream>
void logSomeMessage(int id, logger &loge,std::string str)
{
                std::stringstream ss;
                ss << "ID " << id << " faild :" << str;
                loge.log(ss.str());

}
int main()
{
                logger _logger;
                std::vector<std::thread> threads;
                std::string str = "wrong";
                /*for (int i = 0; i < 10; i++)
                {
                    threads.push_back(std::thread{ logSomeMessage,i,std::ref(_logger),str });
                }
                for (auto &t : threads) {t.join();}*/
                logSomeMessage(8456, _logger, "wrong");
                return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值