• Boost Thread学习笔记三


    下面先对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 }
  • 相关阅读:
    new delete的内部实现代码
    子串的替换
    求字符串的长度
    TSQL语句学习(四)
    TSQL语句学习(二)
    杭电acm1036
    杭电acm2032
    杭电acm2045
    杭电acm2072
    杭电acm1029
  • 原文地址:https://www.cnblogs.com/lidabo/p/3796135.html
Copyright © 2020-2023  润新知