下面先对condition_impl进行简要分析。
condition_impl在其构造函数中会创建两个Semaphore(信号量):m_gate、m_queue,及一个Mutex(互斥体,跟boost::mutex类似,但boost::mutex是基于CriticalSection<临界区>的):m_mutex,其中:
m_queue
相当于当前所有等待线程的等待队列,构造函数中调用CreateSemaphore来创建Semaphore时,lMaximumCount参数被指定为(std::numeric_limits<long>::max)(),即便如此,condition的实现者为了防止出现大量等待线程的情况(以至于超过了long的最大值),在线程因执行condition::wait进入等待状态时会先:
WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
以等待被唤醒,但很难想象什么样的应用需要处理这么多线程。
m_mutex
用于内部同步的控制。
但对于m_gate我很奇怪,我仔细研究了一下condition_imp的实现,还是不明白作者引入m_gate这个变量的用意何在,既然已经有了用于同步控制的m_mutex,再引入一个m_gate实在让我有点不解。

以下是condition::wait调用的do_wait方法简化后的代码:

1 template <typename M>
2 void do_wait(M& mutex)
3 {
4     m_impl.enter_wait();
5     lock_ops::unlock(mutex, state);    //对传入的scoped_lock对象解锁,以便别的线程可以对其进行加锁,并执行某些处理,否则,本线程等待的condition永远不会发生(因为没有线程可以获得访问资源的权利以使condition发生)
6     m_impl.do_wait();    //执行等待操作,等待其它线程执行notify_one或notify_all操作以获得
7     lock_ops::lock(mutex, state);    //重新对scoped_lock对象加锁,获得独占访问资源的权利
8 }

condition::timed_wait的实现方法与此类似,而notify_one、notify_all仅将调用请求转发给m_impl,就不多讲了。

虽然condition的内部实现比较复杂,但使用起来还是比较方便的。下面是一个使用condition的多Producer-多Consumer同步的例子:

  1 #include <boost/thread/thread.hpp>
  2 #include <boost/thread/mutex.hpp>
  3 #include <boost/thread/condition.hpp>
  4 #include <boost/thread/xtime.hpp>
  5 
  6 #include <iostream>
  7 #include <time.h> // for time()
  8 
  9 #include <Windows.h>    // for Sleep, change it for other platform, we can use
 10                         // boost::thread::sleep, but it's too inconvenient.
 11 
 12 typedef boost::mutex::scoped_lock scoped_lock;
 13 boost::mutex io_mutex;
 14 
 15 class Product
 16 {
 17     int num;
 18 public:
 19     Product(int num) : num(num) {}
 20 
 21     friend std::ostream& operator<< (std::ostream& os, Product& product)
 22     {
 23         return os << product.num;
 24     }
 25 };
 26 
 27 class Mediator
 28 {
 29 private:
 30     boost::condition cond;
 31     boost::mutex mutex;
 32 
 33     Product** pSlot;    // product buffer/slot
 34     unsigned int slotCount,    // buffer size
 35         productCount; // current product count
 36     bool stopFlag;    // should all thread stop or not
 37 
 38 public:
 39     Mediator(const int slotCount) : slotCount(slotCount), stopFlag(false), productCount(0)
 40     {
 41         pSlot = new Product*[slotCount];
 42     }
 43 
 44     virtual ~Mediator()
 45     {
 46         for (int i = 0; i < static_cast<int>(productCount); i++)
 47         {
 48             delete pSlot[i];
 49         }
 50         delete [] pSlot;
 51     }
 52 
 53     bool Stop() const { return stopFlag; }
 54     void Stop(bool) { stopFlag = true; }
 55 
 56     void NotifyAll()    // notify all blocked thread to exit
 57     {
 58         cond.notify_all();
 59     }
 60 
 61     bool Put( Product* pProduct)
 62     {
 63         scoped_lock lock(mutex);
 64         if (productCount == slotCount)
 65         {
 66             {
 67                 scoped_lock lock(io_mutex);
 68                 std::cout << "Buffer is full. Waiting" << std::endl;
 69             }
 70             while (!stopFlag && (productCount == slotCount))
 71                 cond.wait(lock);
 72         }
 73         if (stopFlag) // it may be notified by main thread to quit.
 74             return false;
 75 
 76         pSlot[ productCount++ ] = pProduct;
 77         cond.notify_one();    // this call may cause *pProduct to be changed if it wakes up a consumer
 78 
 79         return true;
 80     }
 81 
 82     bool Get(Product** ppProduct)
 83     {
 84         scoped_lock lock(mutex);
 85         if (productCount == 0)
 86         {
 87             {
 88                 scoped_lock lock(io_mutex);
 89                 std::cout << "Buffer is empty. Waiting" << std::endl;
 90             }
 91             while (!stopFlag && (productCount == 0))
 92                 cond.wait(lock);
 93         }
 94         if (stopFlag) // it may be notified by main thread to quit.
 95         {
 96             *ppProduct = NULL;
 97             return false;
 98         }
 99 
100         *ppProduct = pSlot[--productCount];
101         cond.notify_one();
102 
103         return true;
104     }
105 };
106 
107 class Producer
108 {
109 private:
110     Mediator* pMediator;
111     static unsigned int num;
112     unsigned int id;    // Producer id
113 
114 public:
115     Producer(Mediator* pMediator) : pMediator(pMediator) { id = num++; }
116 
117     void operator() ()
118     {
119         Product* pProduct;
120         srand( (unsigned)time( NULL ) + id );    // each thread need to srand differently
121         while (!pMediator->Stop())
122         {
123             pProduct = new Product( rand() % 100 );
124             // must print product info before call Put, as Put may wake up a consumer
125             // and cause *pProuct to be changed
126             {
127                 scoped_lock lock(io_mutex);
128                 std::cout << "Producer[" << id << "] produces Product["
129                     << *pProduct << "]" << std::endl;
130             }
131             if (!pMediator->Put(pProduct))    // this function only fails when it is notified by main thread to exit
132                 delete pProduct;
133 
134             Sleep(100);
135         }
136     }
137 };
138 
139 unsigned int Producer::num = 1;
140 
141 class Consumer
142 {
143 private:
144     Mediator* pMediator;
145     static unsigned int num;
146     unsigned int id;    // Consumer id
147 
148 public:
149     Consumer(Mediator* pMediator) : pMediator(pMediator) { id = num++; }
150 
151     void operator() ()
152     {
153         Product* pProduct = NULL;
154         while (!pMediator->Stop())
155         {
156             if (pMediator->Get(&pProduct))
157             {
158                 scoped_lock lock(io_mutex);
159                 std::cout << "Consumer[" << id << "] is consuming Product["
160                     << *pProduct << "]" << std::endl;
161                 delete pProduct;
162             }
163 
164             Sleep(100);
165         }
166     }
167 };
168 
169 unsigned int Consumer::num = 1;
170 
171 int main()
172 {
173     Mediator mediator(2);    // we have only 2 slot to put products
174 
175     // we have 2 producers
176     Producer producer1(&mediator);
177     boost::thread thrd1(producer1);
178     Producer producer2(&mediator);
179     boost::thread thrd2(producer2);
180     // and we have 3 consumers
181     Consumer consumer1(&mediator);
182     boost::thread thrd3(consumer1);
183     Consumer consumer2(&mediator);
184     boost::thread thrd4(consumer2);
185     Consumer consumer3(&mediator);
186     boost::thread thrd5(consumer3);
187 
188     // wait 1 second
189     Sleep(1000);
190     // and then try to stop all threads
191     mediator.Stop(true);
192     mediator.NotifyAll();
193 
194     // wait for all threads to exit
195     thrd1.join();
196     thrd2.join();
197     thrd3.join();
198     thrd4.join();
199     thrd5.join();
200 
201     return 0;
202 }

Boost Thread学习笔记三的更多相关文章

  1. Boost Thread学习笔记

    thread自然是boost::thread库的主 角,但thread类的实现总体上是比较简单的,前面已经说过,thread只是一个跨平台的线程封装库,其中按照所使用的编译选项的不同,分别决定使用 W ...

  2. Boost Thread学习笔记五

    多线程编程中还有一个重要的概念:Thread Local Store(TLS,线程局部存储),在boost中,TLS也被称作TSS,Thread Specific Storage.boost::thr ...

  3. Boost Thread学习笔记四

    barrierbarrier类的接口定义如下:  1 class barrier : private boost::noncopyable   // Exposition only 2 { 3 pub ...

  4. Boost Thread学习笔记二

    除了thread,boost种:boost::mutexboost::try_mutexboost::timed_mutexboost::recursive_mutexboost::recursive ...

  5. 学习笔记(三)--->《Java 8编程官方参考教程(第9版).pdf》:第十章到十二章学习笔记

    回到顶部 注:本文声明事项. 本博文整理者:刘军 本博文出自于: <Java8 编程官方参考教程>一书 声明:1:转载请标注出处.本文不得作为商业活动.若有违本之,则本人不负法律责任.违法 ...

  6. muduo网络库学习笔记(三)TimerQueue定时器队列

    目录 muduo网络库学习笔记(三)TimerQueue定时器队列 Linux中的时间函数 timerfd简单使用介绍 timerfd示例 muduo中对timerfd的封装 TimerQueue的结 ...

  7. Oracle学习笔记三 SQL命令

    SQL简介 SQL 支持下列类别的命令: 1.数据定义语言(DDL) 2.数据操纵语言(DML) 3.事务控制语言(TCL) 4.数据控制语言(DCL)  

  8. [Firefly引擎][学习笔记三][已完结]所需模块封装

    原地址:http://www.9miao.com/question-15-54671.html 学习笔记一传送门学习笔记二传送门 学习笔记三导读:        笔记三主要就是各个模块的封装了,这里贴 ...

  9. JSP学习笔记(三):简单的Tomcat Web服务器

    注意:每次对Tomcat配置文件进行修改后,必须重启Tomcat 在E盘的DATA文件夹中创建TomcatDemo文件夹,并将Tomcat安装路径下的webapps/ROOT中的WEB-INF文件夹复 ...

随机推荐

  1. 独立搭建zookeeper

    1.如果你装了带有zookeeper的Hbase版本,先把hbase-env.sh   export HBASE_MANAGES_ZK=false 设置为false 见下图 2.下载安装zookeep ...

  2. POJ 1861 Network (模版kruskal算法)

    Network Time Limit: 1000MS Memory Limit: 30000K Total Submissions: Accepted: Special Judge Descripti ...

  3. 0.关于TCP协议的一些总结

    接触unix网络编程一年多了,偶尔用户态进程表现出一些不能理解的现象,因此将<TCP/IP协议卷1>TCP协议相关的章节通读了一遍,总结了一下相关的知识点. 1.TCP数据报格式 TCP封 ...

  4. 分布式文件系统GlusterFS

    转自于:http://www.cnblogs.com/zitjubiz/archive/2012/11/30/Distributed_File_System_glusterFS.html Gluste ...

  5. File 操纵目录

    mkdir()   创建目录 不可及联创建    即父路径中一旦有不存在文件夹  即创建失败 mkdirs() 创建目录,及联创建 list() 列出目录内所包含的文件名(string) listFi ...

  6. Android学习笔记:Activity生命周期详解

    进行android的开发,必须深入了解Activity的生命周期.而对这个讲述最权威.最好的莫过于google的开发文档了. 本文的讲述主要是对 http://developer.android.co ...

  7. EasyUi 中datagrid 实现查询方法

    1.在初始化表格方法中添加传入參数,例如以下: //初始化表格 function initTable(<strong><span style="color:#ff6666; ...

  8. 动态链接库dll的 静态加载 与 动态加载

    dll 两种链接方式  : 动态链接和静态链接(链接亦称加载) 动态链接是指在生成可执行文件时不将所有程序用到的函数链接到一个文件,因为有许多函数在操作系统带的dll文件中,当程序运行时直接从操作系统 ...

  9. 【Unity技巧】使用单例模式Singleton

    这几天想把在实习里碰到的一些好的技巧写在这里,也算是对实习的一个总结.好啦,今天要讲的是在Unity里应用一种非常有名的设计模式——单例模式. 开场白 单例模式的简单介绍请看前面的链接,当然网上还有很 ...

  10. Ubuntu下SVN命令行递归加入文件夹文件(免去一个一个的加入 --force)

    因为在Linux下一直没有找到好的svn工具(类似于TortiseSVN的).当然eSVN这些也不错,但就是使用上认为还不是很习惯.终于还是选择了svn原始的命令行工具来进行版本号控制操作. 命令行的 ...