boost多线程编程(三)

这次主要是对多线程编程中的条件变量篇章做一个简单的总结。用于记录自己阅读boost库编程指南,不免有些理解不透的地方,望大家见谅并且指出。

一.条件变量的简单介绍

1.条件变量是利用线程间共享的全局变量来进行同步的一种机制,它的实现主要有两个动作:

     (1).一个线程等待条件变量的成立,而被挂起。

     (2).另一个线程操作条件变量,使得条件变量的成立,并且给出条件成立的信号,唤醒该睡眠线程。

2.条件变量的两种类型:

    (1).condition_variable:必须与std::unique_lock配合使用

    (2)..condition_variable_any:更加通用的条件变量,可以与任意类型的锁配合使用,其他的与上面基本一样

3.成员函数:

    (1).notify_one通知其中一个等待线程

    (2).notify_all 通知所有的等待线程

    (3).wait 阻塞当前线程,直到被唤醒

    (4).wait_for 阻塞当前线程直到被唤醒或超过指定的等待时间(时间长度)

    (5).wait_until 阻塞当前线程直到被唤醒或到达指定的时间(时间点)

4.条件变量要与互斥变量的结合使用

(1).条件变量的条件检测 存在一个资源竞争的现象,如(举个生产者和消费者的例子),生产者不断的向队列中添加数据,消费者不断的从队列中取出数据,对条件变量进行检测的时候,需要锁住队列,以免对生产者或者消费者条件检测时候,另一方正在操作队列。所以说条件变量的检测是在互斥锁的保护下进行的。

(2).一个线程等待条件变量的成立,被挂起阻塞。此时会释放锁,其中一个线程获取到锁变量,并且操作条件,使得条件变量变得成立。


二.来看一个例子,这个例子是比较经典的一个例子,生产者和消费者例子。

#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <stack>


using namespace std;
class buffer  
{  
    private:  
        boost::mutex mu, io_mu; //互斥变量,配合条件变量来使用的
		
        boost::condition_variable_any cond_get;  //写入条件变量
	boost::condition_variable_any cond_put;  //读取条件变量
		
        std::stack<int> stk;                    //栈容器
        int un_read, capacity;  
  
        bool is_full()                         //满条件
        {  
            return un_read == capacity;  
        }  
        bool is_empty()                       //栈为空
        {  
            return un_read == 0;  
        }  
	
    public:  
        buffer(size_t n):un_read(0), capacity(n){}  
        void put(int x)  
        {  
            {  										
               boost:: mutex::scoped_lock lock(mu);                     //锁住后,进行条件变量的检测
                while(is_full())  					//判断条件,为啥要用while ? 不用if?
                {  
                    {  								
                        boost::mutex::scoped_lock lock(io_mu);  
                        std::cout << "full waiting..." << std::endl;  
                    }  
                    cond_put.wait(mu);  
                }                     
                stk.push(x);  //stack容器不满的时候,push进去
                {  
                    boost::mutex::scoped_lock lock(io_mu);  
                    std::cout << "put " << x << std::endl;  
                }  
                ++un_read;  //push 增加一个计数
            }  
            cond_get.notify_one();  //唤醒某个被阻塞的(如果有)消费者线程来读取数
        }  
        void get(int& x)  
        {  
            {  
                boost::mutex::scoped_lock lock(mu);  
  
                while(is_empty())  
                {  
                    {  
                        boost::mutex::scoped_lock lock(io_mu);  
                        std::cout << "empty waiting..." << std::endl;  
                    }  
  
                    cond_get.wait(mu);  
                }  
                --un_read;  
                x = stk.top();  
                {  
                    boost::mutex::scoped_lock lock(io_mu);  
                    std::cout << "get " << x << std::endl;  
                }  
                stk.pop();  
            }  
            cond_put.notify_one();  //只通知其中的某一个线程
        }  
};  
void producer(int n, buffer& buf)  
{  
    for(int i = 0; i < n; ++i)  
    {  
        buf.put(i);  
    }  
}
void consumer(int n, buffer& buf)  
{  
    int x;  
    for(int i = 0; i < n; ++i)  
    {  
        buf.get(x);  
    }  
}  
  
int main()  
{  
   buffer buf(5);  
  
   boost::thread t1(producer, 10, ref(buf));  
   boost::thread t2(producer, 10, ref(buf));
   boost::thread t3(consumer, 20, ref(buf));  
  
   t1.join();  
   t2.join();  
   t3.join();  
  
   return 0;  
}  

说到条件变量这块,网上大多数都是这个例子。我们先看下生产者void put()函数,boost:: mutex::scoped_lock lock(mu); 主要是用于检测stack是否满了,检测这个条件时候,需要锁住当前资源。以免在检测时候,消费者操作statck容器。while(is_full())进行判断条件,当statck满的时候,满足条件,此时cond_put.wait(mu); 会阻塞当前线程,并同时释放锁mu,释放锁mu主要是为了让其他的线程得到锁,能操作statck容器。此时,消费者会得到锁,while(is_empty())不满足条件,取出一个数据后,执行cond_put.notify_one(); 通知其中一个阻塞的生产者线程,并且释放锁。其中一个生产者得到通知的信号后,立即重新获取锁,往下执行。这里面有个问题。为什么条件变量的检测不用 if(is_full()) , 而是使用 while(is_full())。下面作一个简单的解释。

在多个生产者和多个消费者这种场景中,其中一个生产者获取锁,并且对statck做了条件判断(此时statck是full) ,阻塞了当前线程,并且释放锁,此时,其他的生产者也有可能会得到这个锁,并且阻塞自己的当前的线程,后面的消费者得到这个锁的时候,进行条件判断(stack 不是empty)进行消费,在statck中取出一个数据后,唤醒其中一个等待的生产者线程,且释放锁。好,在这里我们想一想。如果唤醒的是生产者线程1,但是锁被生产者线程2获取,此时生产者线程2 会检测条件不满足,向statck容器中添加一个数据。但是被唤醒的是生产者线程1,如果我们是用 If 来进行条件变量检测的话,此时会往下执行,再次向已经full的statck中添加数据。(会出错)。所以这个地方不能用if 来进行判断,需要使用while来再次对条件判断一次。

难免会有些解释不妥的地方,希望广大的博友给出建议。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Boost库是一个跨平台的C++库,提供了许多多线程编程的工具和类。下面是使用Boost库进行多线程编程的一些方法: 1. 创建线程 ```cpp #include <boost/thread.hpp> void my_thread_func() { // 线程执行的代码 } int main() { // 创建新线程 boost::thread my_thread(my_thread_func); // 等待线程结束 my_thread.join(); return 0; } ``` 2. 线程同步和互斥 ```cpp #include <boost/thread.hpp> boost::mutex my_mutex; void my_thread_func() { // 申请互斥锁 boost::mutex::scoped_lock lock(my_mutex); // 互斥锁保护的代码 } int main() { // 创建新线程 boost::thread my_thread(my_thread_func); // 等待线程结束 my_thread.join(); return 0; } ``` 3. 线程池 ```cpp #include <boost/thread.hpp> #include <boost/bind.hpp> void my_thread_func(int arg) { // 线程执行的代码 } int main() { // 创建线程池 boost::thread_pool my_thread_pool(4); // 提交任务到线程池 for (int i = 0; i < 10; ++i) { my_thread_pool.submit(boost::bind(my_thread_func, i)); } // 等待任务完成 my_thread_pool.wait(); return 0; } ``` 4. 条件变量 ```cpp #include <boost/thread.hpp> #include <boost/date_time.hpp> boost::mutex my_mutex; boost::condition_variable my_cond_var; void my_thread_func() { // 申请互斥锁 boost::mutex::scoped_lock lock(my_mutex); // 等待条件变量 my_cond_var.wait(lock); // 条件满足后继续执行 } int main() { // 创建新线程 boost::thread my_thread(my_thread_func); // 等待一段时间 boost::this_thread::sleep(boost::posix_time::seconds(2)); // 通知条件变量 my_cond_var.notify_one(); // 等待线程结束 my_thread.join(); return 0; } ``` 以上是使用Boost库进行多线程编程的一些方法,可以根据实际需求进行选择和组合,以实现更加复杂的多线程应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值