http://www.cnblogs.com/wxquare/p/6736202.html

还没开始 留个链接

使用c++11 thread支持实现  一个生产者消费者模型

下面是一个生产者消费者问题,来介绍condition_variable的用法。当线程间的共享数据发生变化的时候,可以通过condition_variable来通知其他的线程。消费者wait 直到生产者通知其状态发生改变,Condition_variable是使用方法如下:      运行过程如下!!!!!!!!!

·当持有锁之后,线程调用wait

·wait解开持有的互斥锁(mutex),阻塞本线程,并将自己加入到唤醒队列中

·当收到通知(notification),该线程从阻塞中恢复,并加入互斥锁队列(mutex queue)

 .线程被唤醒之后继续持有锁运行

Condition variable有两种类型:condition_variable 和 condition_variable_any,

前一种效率更高,但是使用不够灵活,只支持std::unique_lock<std::mutex>类型的互斥锁;

后一种比较灵活,支持所有类型的锁,但是效率稍微低一些。

有一点需要注意的是使用condition variable进行通信的线程,condition variable 需要使用相同的互斥信号量(mutex)。

 例子:!!!! 

#include <thread>
#include <iostream>
#include <mutex>
#include <queue>
#include <condition_variable>
#include <atomic>
using namespace std;
int main()
{
mutex lockBuffer; //申明互斥信号量
volatile bool ArretDemande = false; //使生产、消费过程的结束
queue<long> buffer;
condition_variable_any cndNotifierConsommateurs;//condition variable
condition_variable_any cndNotifierProducteur; thread ThreadProducteur([&]()//生产者线程
{
std::atomic<long> interlock;//对interlock的操作将是原子的
interlock=;
while(true)
{
std::this_thread::sleep_for (chrono::milliseconds ());
long element=interlock.fetch_add ();//【1】
lockBuffer.lock ();
while(buffer.size()== && ArretDemande ==false)
{
cndNotifierProducteur.wait (lockBuffer);//【2】
}
if (ArretDemande==true)
{
lockBuffer.unlock ();
cndNotifierConsommateurs.notify_one ();//【3】
break;
}
buffer.push(element);
cout << "Production unlement :" << element << " size :" << buffer.size() << endl;
lockBuffer.unlock ();
cndNotifierConsommateurs.notify_one ();
} } ); thread ThreadConsommateur([&]()
{
while(true)
{
lockBuffer.lock ();
while(buffer.empty () && ArretDemande==false)
{
cndNotifierConsommateurs.wait(lockBuffer);
}
if (ArretDemande==true && buffer.empty ())
{
lockBuffer.unlock();
cndNotifierProducteur.notify_one ();
break;
}
long element=buffer.front();
buffer.pop ();
cout << "Consommation element :" << element << " size :" << buffer.size() << endl;
lockBuffer.unlock ();
cndNotifierProducteur.notify_one ();
}
} ); std::cout << "Pour arreter pressez [ENTREZ]" << std::endl;
getchar();
std::cout << "Arret demande" << endl
ArretDemande=true;
ThreadProducteur.join();
ThreadConsommateur.join();
cout<<"Main Thread"<<endl;
return ;
}

运行结果:

这个 不是我的 linux下的运行样子     我运行的结果类似这样   意思相同!!!!!!!

对程序进行一下说明,程序中有三个线程,主线程、生产者线程、消费者线程,三个线程之间乱序执行,通过一些全局变量来控制他们的执行顺序。

主线程的作用是控制生产消费过程是否结束,当程序运行之后,主线程通过getchar()接收一个输入,接收到输入后会将ArretDemande设置为true,另外两个线程会终止。

生产者线程将生产出来的数据放在一个queue类型的buffer中,并解锁,通知消费之线程,buffer中最多“能”存10个数据,如果buffer中已经有10个数据还没有被取走,则会通知消费者线程“消费”,如果ArretDmande被置位,则打开锁,并通知消费之线程。消费者线程主要是将buffer中的数据取出来,当buffer为空的时候阻塞自己,并通知生产者线程,当ArretDemande被置位,且已经消费完产品则解锁,并通知生产者线程。需要注意的是需要通信的生产者和消费者这两个线程通过condition variable来实现通信,必须操作同一个mutex,这里是lockbuffer,并且每次Notify都会打开当前锁。

程序中对interlock进行的操作是原子的,interlock.fet_add(N),效果是将interlock加N,然后返回interlock在加N之前的值,atomic类型是通过一定的内存顺序规则来实现这个过程的。

虽然conditon_variable 只能支持std::unique_lock<std::mutex>类型的互斥锁,但是在大部分情况下已经够用,而且使用std::unique_lock<std::mutex>会比较简单,因为std::unique_lock<std::mutex>在声明的时候就会初始化,在生命周期结束之后就会自动解锁,因此我们不用太花精力来考虑什么时候解锁。

例子!!!!!!!!!

#include <condition_variable>
#include <mutex>
#include <thread>
#include <iostream>
#include <queue>
#include <chrono> int main()
{
std::queue<int> produced_nums;
std::mutex m;;
std::condition_variable cond_var;
bool done = false;
bool notified = false;//这个变量在每一个线程中 是每个线程所独有的 std::thread producer([&]() {
for ( int i = ; i < ; ++i) {
std::this_thread::sleep_for(std::chrono:: seconds());
std:: unique_lock<std::mutex > lock(m); //May lock mutex after construction, unlock before destruction.
std::cout << "producing " << i << '\n' ;
       std::cout<<notified<<'\n';//自己 添加的线程的局部变量检测 参数 验证局部变量线程独享!!!!!
produced_nums.push(i);
notified = true;
       std::cout<<notified<<'\n';//同上
       cond_var.notify_one();
} done = true;  //运行到这里 生产其实已经结束了
cond_var.notify_one();// 防止消费者卡死 唤醒最后一个消费者结束 这步需要注意!!!!!!!! 有时候 运行会卡住
});
//cond_var.notify_one();
std::thread consumer([&]() {
while (!done) {
std:: unique_lock<std::mutex > lock(m);
while (!notified) { // loop to avoid spurious wakeups 就是说生产者已经生产了 现在队列有任务 不为空 可以去消费了 不需要挂起了!!!!!!!
cond_var.wait(lock);
}
while (!produced_nums.empty()) {    //当队列不为空 开始消费了
std::cout << "consuming " << produced_nums.front() << '\n';
produced_nums.pop();
}
notified = false;
}
}); producer.join();
consumer.join(); return ;
} 运行结果:
producing 0
consuming 0
producing 1
consuming 1
producing 2
consuming 2
producing 3
consuming 3
producing 4
consuming 4

以上两个例子  验证了c++11的不同的条件变量  对应的不同的锁   其中有一个锁  无需释放   对应的条件变量 则  不同!!!!!!

来一个教科书的 线程解决生产者消费者问题的demo

#include<stdio.h>
#include<pthread.h>
#include<unistd.h> #define MAX 10000000 //需要生产的数量
pthread_mutex_t the_mutex; //全局锁
pthread_cond_t condc, condp;//全局条件变量
int buffer = ; //全局共享变量 void *producer(void*ptr){//生产数据
int i;
for(i=;i<=MAX;i++){
pthread_mutex_lock(&the_mutex);//互斥使用 缓冲区buffer
while(buffer !=)pthread_cond_wait(&condp,&the_mutex);
buffer=i; //将数据放入缓冲区
printf("Is producering %d\n",buffer);
pthread_cond_signal(&condc);//唤醒消费者
pthread_mutex_unlock(&the_mutex);//释放锁 就是释放了缓冲区buffer
}
pthread_exit();//over 线程
} void *consumer(void *ptr){//消费数据
int i;
for(i=;i<=MAX;i++){
sleep();
pthread_mutex_lock(&the_mutex);//互斥使用缓冲区
printf("Is consumering \n");
while(buffer==)pthread_cond_wait(&condc,&the_mutex);
buffer = ; //从缓冲区取出数据
pthread_cond_signal(&condp);//唤醒生产者
pthread_mutex_unlock(&the_mutex);////释放锁 就是释放了缓冲区buffer
}
pthread_exit();//over 线程
} int main(int argc,char**argv)
{
pthread_t pro,con;
pthread_mutex_init(&the_mutex,);
pthread_cond_init(&condc,);
pthread_cond_init(&condp,); pthread_create(&con,,consumer,);
pthread_create(&pro,,producer,); pthread_join(pro,);//回收线程资源
pthread_join(con,); pthread_cond_destroy(&condc);//销毁条件变量
pthread_cond_destroy(&condp); pthread_mutex_destroy(&the_mutex);//销毁锁 return ;
}
已经进过测试 Linux Ok!!!!!!!!!!!!!!

就先到这里吧!!!

c++11 thread的学习的更多相关文章

  1. 漫谈C++11 Thread库之原子操作

    我在之前一篇博文<漫谈C++11 Thread库之使写多线程程序>中,着重介绍了<thread>头文件中的std::thread类以及其上的一些基本操作,至此我们动手写多线程程 ...

  2. java基础知识回顾之java Thread类学习(十)--线程的状态以及转化使用的方法介绍

       线程的概述:         线程是程序的多个执行路径,执行调度的单位,依托于进程存在.线程不仅可以共享进程的内存,而且还拥有一个属于自己的内存空间,这段内存空间叫做线程栈,是建立线程的时候由系 ...

  3. HTML5初学者福利!11个在线学习网站推荐

    HTML5初学者福利!11个在线学习网站推荐 HTML5的强大及流行趋势,让更多的人想要系统的对它进行学习.而大多数人获取HTML5知识的重要途径都是网络,不过面对五花八门的搜索结果,是不是觉得摸不着 ...

  4. DirectX 11游戏编程学习笔记之8: 第6章Drawing in Direct3D(在Direct3D中绘制)(习题解答)

            本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com         注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候 ...

  5. DirectX 11游戏编程学习笔记之6: 第5章The Rendering Pipeline(渲染管线)

            本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com         注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候 ...

  6. C++11 Thread多线程的学习心得与问题

    C++11 ,封装了thread的多线程的类,这样对多线程的使用更加方便. 多线程的原理我不加赘述,可以参看操作系统等参考书. 多线程代码可以最大化利用计算机性能资源,提高代码的运行效率,是常用优化方 ...

  7. c++11: <thread>学习

    <thread>头文件中包含thread类与this_thread命名空间,下面逐一介绍. thread类 1. 构造函数 (1)默认构造函数 thread() noexcept; 默认构 ...

  8. 漫谈c++11 Thread库之使写多线程程序

    c++11中最重要的特性之一就是对多线程的支持了,然而<c++ primer>5th却没有这部分内容的介绍,着实人有点遗憾.在网上了解到了一些关于thread库的内容.这是几个比较不错的学 ...

  9. c++11 线程池学习笔记 (一) 任务队列

    学习内容来自一下地址 http://www.cnblogs.com/qicosmos/p/4772486.html github https://github.com/qicosmos/cosmos ...

随机推荐

  1. SpringMVC拦截器的配置与使用详解

         一.SpringMVC拦截器简介      Spring MVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理.在springmvc中,定义拦截 ...

  2. linux 下errno各个值的意义(转) errno.h

    strerror(errno):获取errno对应的错误 查看错误代码errno是调试程序的一个重要方法.当linux C api函数发生异常时,一般会将errno变量(需include errno. ...

  3. 树莓派与 Python —— GPIO

    首先来直观地认识树莓派提供的 40 个引脚(GPIO,general purpose i/o,接收外界输入,并向外界提供运算处理后的输出): 1. 安装 从远程库(repositories)中下载安装 ...

  4. 每天一个Linux命令:目录

    版权声明 更新:2017-04-19博主:LuckyAlan联系:liuwenvip163@163.com声明:吃水不忘挖井人,转载请注明出处! 1 文章介绍 在使用Linux的过程中总是发现有一些L ...

  5. Father Christmas flymouse

    Father Christmas flymouse Time Limit: 1000MS   Memory Limit: 131072K Total Submissions: 3479   Accep ...

  6. 原生及jq方式使用ajax

    1.原生js实现Ajax方法: // 封装ajax()方法 function ajax(url,fnSucc,fnFaild){ //1.创建Ajax 对象 if(window.XMLHttpRequ ...

  7. stm32之开发入门

    一.开发环境配置 在开发stm32应用之前,我们需要先配置好开发环境. 首先从keil官网下载keil MDK-ARM软件包(v5版本与v4版本不同,v5版本需要下载额外的stm32芯片包)和芯片包( ...

  8. QListWidget笔记

    1.头文件:#include <QListWidget> 2.继承自:QListView 3.基本代码: #include "mainwindow.h" #includ ...

  9. day1 java基础回顾-IO流

    IO流的分类 注:这几个类都是抽象类. IO解决问题: 解决设备与设备之间 的数据传输问题. 比如: 硬盘--->内存 内存----->硬盘 字节流: 输入字节流:---------| I ...

  10. VIM显示utf-8乱码

    找到vim的根目录下的vimrc文件打开,加入下面三行,保存.重开vim即可. set encoding=utf-8 set langmenu=zh_CN.UTF-8 language message ...