1相关理念

(1)类名

条件变量和互斥变量都是boost库中被封装的类。

(2)条件变量

条件变量是thread库提供的一种等待线程同步的机制,可实现线程间的通信,它必须与互斥量配合使用,等待另一个线程中某个事件发生后本线程才能继续执行。

(3)互斥变量

互斥量是一种用于多线程编程的手段,它可以在多线程编程中防止多个线程同时操作共享资源[或称为临界区 ]。思想为:在每个线程开始的第一条语句使用获取互斥变量“锁有权”的语句,一旦一个线程[线程1]锁住了互斥量,那么其它线程只有等待线程1解锁互斥量后且另一线程[线程2]又获取到互斥变量的“锁有权”后才能运行这个线程[线程2]后面的代码。

(4)互斥量有可能的缺点

[1]互斥变量的使用让线程整个整个的运行。

[2]如果“同时”创建多线程,则首先获取到互斥变量“锁有权”的线程是不定的。

(5)条件变量的简单应用场景

有时候我们需要先运行某个线程一会儿后才能运行另一个线程,或者是需要先运行某个线程[线程1]一会儿后必须运行另一个线程[线程2]后线程1才能够继续运行。C++ boost库对条件变量的封装 就是来解决这些问题的。

2 条件变量的使用机制总结

C++boost 的thread库提供两种条件变量对象condition_variable及condition_variable_any,由于后者能够适用于更广泛的互斥量类型,所以一般用condition_variable_any,其类摘要如下:

  1. class condition_variable_any
  2. {
  3. public:
  4. void notify_one();
  5. void notify_all();
  6. template <typename  lock_type>
  7. void wait(lock_type  &lock);
  8. template<typename lock_type, typename  predicate_type>
  9. void wait(lock_type  &lock,predicate_type  predicate);
  10. template<typename lock_type, typename  duration_type>
  11. bool timed_wait(lock_type  &lock, duration_type  const&  rel_time);
  12. }

条件变量condition_variable_any中只封装了]notify_one(),notify_all()和wait()系列两类函数。

2.1参考书对条件变量的描述

拥有条件变量的线程先锁定互斥量,然后循环检查某个条件,如果条件不满足,那么就调用成员函数wait()等至条件满足。而其它线程处理条件变量要求的条件,当条件满足时调用它的成员函数notify_one()或notify_all(),以通知所有正在等待条件变量的线程停止等待继续执行。

其实这一小段话就将condition_variable_any类摘要的使用机制给描述了,但是不得不承认我并没有读懂,所以还得继续写程序验证一下条件变量到底封装了怎么一个机制。

2.2实践总结笔记

(1)简单使用条件变量步骤

[1]定义生存期和作用域能够应用于多线程中的条件变量对象和互斥变量对象。条件变量对象的个数据程序需求制定。

condition_variable_any  con_var_1;

condition  variable_anu  con_var_2;

mutex  mu;

[2]每个线程对应函数的第一条语句使用锁定互斥量的语句,最后一条语句使用解锁互斥量的语句。【如果不使用条件变量来实现线程通信,则如此就能够使多线程中单个线程一个接连一个的运行,运行时间和场合的不同,各线程运行的顺序也不同】

void  thread_fun_1()

{

mu.lock();

……

mu.unlock();

}

void  thread_fun_2()

{

mu.lock();

……

mu.unlock();

}

[3]thread_fun_1()输出”123456789”字符串的奇数数字,thread_fun_2()输出字符串的偶数数字,并且用条件变量和多线程来实现

void  thread_fun_1( const  string  &str )
{
mu.lock();
while ( i < str.length() )
{
while( !(i % ) )
{
con_var_1.wait( mu );
}
if ( i < str.length() )
{
cout << "p1:" << str[i] <<"\n";
}
++i;
//i++后一定是奇数,但是如果是此线程先运行,则第一次通知print_2.wait()时它都不曾等待过
con_var_2.notify_one();
}
mu.unlock();
}
void  thread_fun_2( const  string  &str )
{
mu.lock();
while ( i < str.length() )
{
while( i % )
{
      //wait操作会接触对Mutex的锁定
con_var_2.wait( mu );
}
if ( i < str.length() )
{
cout << "p2:" << str[i] <<"\n";
}
++i;
//i++后一定是奇数,但是如果是此线程先运行,则第一次通知print_2.wait()时它都不曾等待过
con_var_1.notify_one();
}
mu.unlock();
}

其中i可以是两个线程函数都能够访问的全局变量。

[4]在主程序中创建两个线程来跑这两个线程函数。

thread  th_1(thread_fun_1, “123456789”);

thread  th_2(thread_fun_2, ”123456789”);

可以使用getchar()函数让运行窗口停留,程序运行效果为目标期待的样子【前提是知道boost库的使用需要包含的头文件及开发环境的配置】:

 

Figure1:条件变量应用于多线程运行结果

(2)程序执行分析[wait与notify]

当不懂得一个程序运行的结果时,那就老老实实从最基本的机制用自己的脑袋将有必要的那部分程序运行一遍。我的笨方法。

  • [1]两个线程不管哪一个先获取到互斥变量mu的“锁有权”,另一个线程的运行就会被阻塞。如线程th_2先获取到互斥变量mu的“锁有权”,那么就进入thread_fun_2内,此时th_1不拥有互斥变量的“锁有权”就会被其线程函数内的mu.lock()语句阻塞。
  • [2]当thread_fun_2打印一次字符到屏幕之上后就会进入以 i%2为条件的while循环中执行”con_var_2.wait( mu);”语句。根据条件变量wait()函数的功能,th_2线程就会开始睡眠[就停留在”con_var_2.wait( mu );”语句处],同时wait(mu)函数还将unlock互斥量mu,在时刻mu.lock(mu)[等待锁定互斥量mu]的线程th_1立马获得互斥量的“锁有权”,然后开始执行线程th_1对应函数thread_fun_1内的内容[如果th_1内没有使用wait代码,那么此次线程th_1将会执行完毕,不是con_var_2.notify_one()函数一执行和th_2中con_var_2.wait()完成通信之后就会立即返回到th_2对应函数thread_fun_2中继续执行,而是会将th_1线程执行完之后再回到th_2(thread_fun_2)的con_var_2.wait()语句处 ,此时con_var_2.wait()函数返回,然后wait函数将再lock互斥变量mu。然后再判断while中的条件,如果条件为假则执行下一条语句,如果while中的条件依然为真,那么重新调用con_var_2.wait()函数继续等待]
  • [3]当th_1d对应函数打印一个偶数数字到屏幕之后,进入while之中执行con_var_1.wait( mu )语句,由于此时线程th_2的”con_var_2.wait( mu );”已经收到过”con_var_1.notify_one();”的通信,所以th_2继续lock  mu,然后执行下一段代码。在++i后,再通知th_1中的con_var_1.wait(mu )函数,等th_2再次发生等待时,th_1中的wait函数属性,重新锁定互斥变量mu,继续执行。如此反复执行代码,直到两个线程都执行完毕为止。
  • [4]不过也发现了一个问题:两个线程初次使用notify_one()函数时,对方线程内都还没有使用过wait函数,那么notify_one()函数初次使用时是个什么状况?或许condition_variable_any在封装了处理这个问题的代码。I do not know now。

(3)条件变量封装机理[wait与notify]

其实这个机制在程序执行分析时已经完全的体现了。不过看起来挺长的样子,语言描述也不流畅。估计我今后也懒得看,还是整理一个比较简洁的版本来概括一下条件变量使用的机理。

  • [1]条件变量类的使用体现在wait和notify_one两个函数之上
  • [2]当在一个线程中用一个条件变量对象1调用wait函数时,它将起到暂时unlock多线程间供用的互斥变量而让本线程陷入等待之中。【由于对互斥变量的unlock,其它的线程会锁定互斥变量】,等其它线程执行完毕,再用条件变量对象1调用notify_one函数时,wait函数就会苏醒,并重新lock互斥变量,继续执行本线程。

总而言之,条件变量是一种逻辑控制,就是给咱提供了两个函数:wait函数用于发出信号并等待[还有unlock/lock机制],notify_one就是通知wait函数不用等了醒来返回吧。当在每个线程中都使用条件变量提供的这种机制时,逻辑上就比较复杂了,但是对于cpu来说很好分清,只要根据运行结果不断的调试,总会调到自己期望的逻辑效果。

3使用条件变量的基础

(1)纯粹的多线程运行

如果在程序中创建了多个线程,不使用互斥变量来约束各线程的运行顺序,那么当某个线程被定义时它就开始运行,在多线程的情况下,各线程以极短的时间交替运行着,可以认为在“同一时间”他们都在运行。

(2)使用互斥变量约束线程的运行

对于使用相同互斥变量的多个线程来说,只有获取到互斥量“锁有权”的线程才能运行,否则就会被阻塞直到获取到了互斥量的“锁有权”。所以,线程是被整个整个依次运行完毕的。而且很有可能是这样:不同时间的运行对应着不同次序的运行,获取互斥变量的顺序不同造成的。

(3)规定线程的运行顺序

在互斥变量的基础之上,使用条件变量就是能实现标题的内容。线程既不是“同时”运行也不是会因为运行环境的不同而造成各线程运行顺序的不同。

(1)~(3)是循序渐进的一个过程。

我想知道

mutex mu;

boost::mutex::scoped_lock lock(mu);和mu.lock()都能加锁,但不知有什么区别?

此次笔记记录完毕。

boost库(条件变量)的更多相关文章

  1. BOOST 条件变量使用

    代码: // boost库 条件变量 使用测试 #include <iostream> #include <boost/thread.hpp> using namespace ...

  2. 并发编程(二):分析Boost对 互斥量和条件变量的封装及实现生产者消费者问题

    请阅读上篇文章<并发编程实战: POSIX 使用互斥量和条件变量实现生产者/消费者问题>.当然不阅读亦不影响本篇文章的阅读. Boost的互斥量,条件变量做了很好的封装,因此比" ...

  3. 并发编程入门(二):分析Boost对 互斥量和条件变量的封装及实现生产者消费者问题

    请阅读上篇文章<并发编程实战: POSIX 使用互斥量和条件变量实现生产者/消费者问题>.当然不阅读亦不影响本篇文章的阅读. Boost的互斥量,条件变量做了很好的封装,因此比" ...

  4. Boost条件变量condition_variable_any

    Boost条件变量可以用来实现线程同步,它必须与互斥量配合使用.使用条件变量实现生产者消费者的简单例子如下,需要注意的是cond_put.wait(lock)是在等待条件满足.如果条件不满足,则释放锁 ...

  5. 转载~kxcfzyk:Linux C语言多线程库Pthread中条件变量的的正确用法逐步详解

    Linux C语言多线程库Pthread中条件变量的的正确用法逐步详解   多线程c语言linuxsemaphore条件变量 (本文的读者定位是了解Pthread常用多线程API和Pthread互斥锁 ...

  6. Linux 下 boost 库的安装,配置个人环境变量

    部分引自: https://blog.csdn.net/this_capslock/article/details/47170313 1. 下载boost安装包并解压缩到http://www.boos ...

  7. boost 条件变量

    // boost 条件变量 // 做个简单的笔记 #include <boost/thread/mutex.hpp> #include <boost/thread/condition ...

  8. muduo网络库源码学习————条件变量

    muduo里的CountDownLatch类实际上是对条件变量condition进行的封装,既可以用于所有子线程等待主线程发起 "起跑" ,也可以用于主线程等待子线程初始化完毕才开 ...

  9. boost 线程、互斥体、条件变量

    1.任何技术都是针对特定场景设计的,也就是说,为了解决某个问题而设计的. 2.考虑下面一种场景:一个小旅馆,只有一个卫生间,有清洁人员,店主人,和旅客.卫生间用完之后,就会自动锁闭,必须取钥匙,才能进 ...

随机推荐

  1. jquery 现实多状态控件 (status & power(2,0)) = power(2,0)

    数据库表设计的时候,会有很些多状态的需求,比如招聘职位需要同时发布到武汉,广州,上海 实现方法有很多种,我选择了在职位表中建一个 int 型字段保存多种状态,这个涉及到一些算法,我要查询武汉和广州的职 ...

  2. google project tango 学习笔记

    google io 2015上 project tango 的演示视频

  3. ASP.NET MVC+WCF+NHibernate+Autofac 框架组合(一)

    学习了Spring.NET+NHibernate的框架,觉得Spring.NET框架不够轻量,配置来配置去的比较头疼,所以把Spring.NET换成了Autofac框架,同时加入WCF框架整了一个组合 ...

  4. yum标准化安装nginx最新版

    yum标准化安装nginx最新版 cat > /etc/yum.repos.d/nginx.repo [nginx] name=nginx repo baseurl=http://nginx.o ...

  5. SimpleDateFormat非线程安全

    文章列表 1)SimpleDateFormat的线程安全问题与解决方案 2)深入理解Java:SimpleDateFormat安全的时间格式化

  6. 测试技能积木-AWK的简要用法

    做测试工作,经常要分析日志,有的时候活儿还很脏很累,比如抽取符合某些pattern的行,重新格式化等等.有的时候,我们需要也创造一些测试用数据文件.基于上述两种原因,在Unix Like 系统上,一些 ...

  7. 分布式人工智能标记语言(DAIML)示例

          DAIML(Distributed Artificial Intelligence Markup Language)是用于分布式人工智能系统中智能语言的标记库.DAIML主要分为Patte ...

  8. js回调

    请先看着一片blog: http://www.jb51.net/article/53027.htm 回调的两种使用方法: 1.一般的传函数.2.匿名函数 3.使用回调函数再使用call方法. 判断一个 ...

  9. 字符串string类型转换成DateTime或DateTime?类型

    常用的Convert.ToDateTime方法 //将含有正确日期格式的string类型转换成DateTime类型 string strDate = "2014-08-01"; D ...

  10. [bzoj 1026]windy数(数位DP)

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1026 分析: 简单的数位DP啦 f[i][j]表示数字有i位,最高位的数值为j的windy数总 ...