请阅读上篇文章《并发编程实战: POSIX 使用互斥量和条件变量实现生产者/消费者问题》。当然不阅读亦不影响本篇文章的阅读

Boost的互斥量,条件变量做了很好的封装,因此比“原生的”POSIX mutex,condition variables好用。然后我们会通过分析boost相关源码看一下boost linux是如何对pthread_mutex_t和pthread_cond_t进行的封装。

首先看一下condition_variable_any的具体实现,代码路径:/boost/thread/pthread/condition_variable.hpp

class condition_variable_any
{
pthread_mutex_t internal_mutex;
pthread_cond_t cond; condition_variable_any(condition_variable_any&);
condition_variable_any& operator=(condition_variable_any&); public:
condition_variable_any()
{
int const res=pthread_mutex_init(&internal_mutex,NULL);
if(res)
{
boost::throw_exception(thread_resource_error());
}
int const res2=pthread_cond_init(&cond,NULL);
if(res2)
{
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
boost::throw_exception(thread_resource_error());
}
}
~condition_variable_any()
{
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
BOOST_VERIFY(!pthread_cond_destroy(&cond));
}

condition_variable_any的构造函数是对于内部使用的mutex和cond的初始化,对应的,析构函数则是这些资源的回收。

BOOST_VERIFY的实现:

#undef BOOST_VERIFY
#if defined(BOOST_DISABLE_ASSERTS) || ( !defined(BOOST_ENABLE_ASSERT_HANDLER) && defined(NDEBUG) )
// 在任何情况下,expr一定会被求值。
#define BOOST_VERIFY(expr) ((void)(expr))
#else
#define BOOST_VERIFY(expr) BOOST_ASSERT(expr)
#endif

因此不同于assert在Release版的被优化掉不同,我们可以放心的使用BOOST_VERITY,因此它的表达式肯定会被求值,而不用担心assert的side effect。
接下来看一下condition_variable_any的核心实现:wait

   template<typename lock_type>
void wait(lock_type& m)
{
int res=0;
{
thread_cv_detail::lock_on_exit<lock_type> guard;
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
guard.activate(m);
res=pthread_cond_wait(&cond,&internal_mutex);
this_thread::interruption_point();
}
if(res)
{
boost::throw_exception(condition_error());
}
}

首先看一下lock_on_exit:

namespace thread_cv_detail
{
template<typename MutexType>
struct lock_on_exit
{
MutexType* m; lock_on_exit():
m(0)
{} void activate(MutexType& m_)
{
m_.unlock();
m=&m_;
}
~lock_on_exit()
{
if(m)
{
m->lock();
}
}
};
}

代码很简单,实现了在调用activate时将传入的lock解锁,在该变量生命期结束时将guard的lock加锁。

接下来的detail::interruption_checker check_for_interruption(&internal_mutex,&cond);是什么意思呢?From /boost/thread/pthread/thread_data.hpp

class interruption_checker
{
thread_data_base* const thread_info;
pthread_mutex_t* m;
bool set; void check_for_interruption()
{
if(thread_info->interrupt_requested)
{
thread_info->interrupt_requested=false;
throw thread_interrupted();
}
} void operator=(interruption_checker&);
public:
explicit interruption_checker(pthread_mutex_t* cond_mutex,pthread_cond_t* cond):
thread_info(detail::get_current_thread_data()),m(cond_mutex),
set(thread_info && thread_info->interrupt_enabled)
{
if(set)
{
lock_guard<mutex> guard(thread_info->data_mutex);
check_for_interruption();
thread_info->cond_mutex=cond_mutex;
thread_info->current_cond=cond;
BOOST_VERIFY(!pthread_mutex_lock(m));
}
else
{
BOOST_VERIFY(!pthread_mutex_lock(m));
}
}
~interruption_checker()
{
if(set)
{
BOOST_VERIFY(!pthread_mutex_unlock(m));
lock_guard<mutex> guard(thread_info->data_mutex);
thread_info->cond_mutex=NULL;
thread_info->current_cond=NULL;
}
else
{
BOOST_VERIFY(!pthread_mutex_unlock(m));
}
}

代码面前,毫无隐藏。那句话就是此时如果有interrupt,那么就interrupt吧。否则,lock传入的mutex,也是为了res=pthread_cond_wait(&cond,&internal_mutex);做准备。

关于线程的中断点,可以移步《【Boost】boost库中thread多线程详解5——谈谈线程中断》。

对于boost::mutex,大家可以使用同样的方法去解读boost的实现,相对于condition variable,mutex的实现更加直观。代码路径:/boost/thread/pthread/mutex.hpp。

namespace boost
{
class mutex
{
private:
mutex(mutex const&);
mutex& operator=(mutex const&);
pthread_mutex_t m;
public:
mutex()
{
int const res=pthread_mutex_init(&m,NULL);
if(res)
{
boost::throw_exception(thread_resource_error());
}
}
~mutex()
{
BOOST_VERIFY(!pthread_mutex_destroy(&m));
} void lock()
{
int const res=pthread_mutex_lock(&m);
if(res)
{
boost::throw_exception(lock_error(res));
}
} void unlock()
{
BOOST_VERIFY(!pthread_mutex_unlock(&m));
} bool try_lock()
{
int const res=pthread_mutex_trylock(&m);
if(res && (res!=EBUSY))
{
boost::throw_exception(lock_error(res));
} return !res;
} typedef pthread_mutex_t* native_handle_type;
native_handle_type native_handle()
{
return &m;
} typedef unique_lock<mutex> scoped_lock;
typedef detail::try_lock_wrapper<mutex> scoped_try_lock;
};
}

boost对于pthread_mutex_t和pthread_cond_t的封装,方便了开发者的使用的资源的安全有效管理。当然,在不同的公司,可能也都有类似的封装,学习boost的源码,无疑可以加深我们的理解。在某些特定的场合,我们也可以学习boost的封装方法,简化我们的日常开发。

最后,奉上简单的生产者、消费者的boost的实现,和前文《并发编程实战: POSIX 使用互斥量和条件变量实现生产者/消费者问题》相比,我们可以看到boost简化了mutex和condition variable的使用。以下代码引自《Boost程序库完全开发指南》:

#include <boost/thread.hpp>
#include <stack>
using std::stack;
using std::cout;
class buffer
{
private:
boost::mutex mu; // 条件变量需要配合互斥量
boost::condition_variable_any cond_put; // 生产者写入
boost::condition_variable_any cond_get; // 消费者读走 stack<int> stk;
int un_read;
int capacity; bool is_full()
{
return un_read == capacity;
}
bool is_empty()
{
return 0 == un_read;
} public:
buffer(size_t capacity) : un_read(0), capacity(capacity)
{}
    void put(int x)
    {         boost::mutex::scoped_lock lock(mu); // 这里是读锁的门闩类         while (is_full())
        {
            cout << "full waiting..." << endl;
            cond_put.wait(mu); // line:51
        }
        stk.push(x);
        ++un_read;         cond_get.notify_one();
    }
    void get(int *x)
    {
        boost::mutex::scoped_lock lock(mu); // 这里是读锁的门闩类         while (is_empty())
        {
            cout << "empty waiting..." << endl;
            cond_get.wait(mu);
        }
        *x = stk.top();
        stk.pop();
        --un_read;         cond_put.notify_one(); // 通知 51line可以写入了
    }
}; buffer buf(5); void producer(int n)
{
    for (int i = 0; i < n; ++i)
    {
        cout << "put : " << i << endl;
        buf.put(i);
    }
} void consumer(int n)
{
    int x;
    for (int i = 0; i < n; ++i)
    {
        buf.get(&x);
        cout << "get : " << x << endl;
    }
} int main()
{
    boost::thread t1(producer, 20);
    boost::thread t2(consumer, 10);
    boost::thread t3(consumer, 10);     t1.join();
    t2.join();
    t3.join();     return 0;
}

最后说一句,condition_variable_any == condition, from /boost/thread/condition.hpp

namespace boost
{
typedef condition_variable_any condition;
}

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

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

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

  2. [转]一个简单的Linux多线程例子 带你洞悉互斥量 信号量 条件变量编程

    一个简单的Linux多线程例子 带你洞悉互斥量 信号量 条件变量编程 希望此文能给初学多线程编程的朋友带来帮助,也希望牛人多多指出错误. 另外感谢以下链接的作者给予,给我的学习带来了很大帮助 http ...

  3. 互斥量、条件变量与pthread_cond_wait()函数的使用,详解(二)

    1.Linux“线程” 进程与线程之间是有区别的,不过linux内核只提供了轻量进程的支持,未实现线程模型.Linux是一种“多进程单线程”的操作系统.Linux本身只有进程的概念,而其所谓的“线程” ...

  4. 生产者-消费者问题:介绍POSIX线程的互斥量和条件变量的使用

    全局初始化互斥量和条件变量(不全局也行,但至少要对线程启动函数可见,这样才能使用.) static pthread_cont_t cond = PTHREAD_COND_INITIALIZER; st ...

  5. 并发编程(一): POSIX 使用互斥量和条件变量实现生产者/消费者问题

    boost的mutex,condition_variable非常好用.但是在Linux上,boost实际上做的是对pthread_mutex_t和pthread_cond_t的一系列的封装.因此通过对 ...

  6. 并发编程入门(一): POSIX 使用互斥量和条件变量实现生产者/消费者问题

    boost的mutex,condition_variable非常好用.但是在Linux上,boost实际上做的是对pthread_mutex_t和pthread_cond_t的一系列的封装.因此通过对 ...

  7. 互斥量、条件变量与pthread_cond_wait()函数的使用,详解(一)

    1. 首先pthread_cond_wait 的定义是这样的 The pthread_cond_wait() and pthread_cond_timedwait() functions are us ...

  8. POSIX 使用互斥量和条件变量实现生产者/消费者问题

    boost的mutex,condition_variable非常好用.但是在Linux上,boost实际上做的是对pthread_mutex_t 和pthread_cond_t的一系列的封装.因此通过 ...

  9. Linux并发与同步专题 (4) Mutex互斥量

    关键词:mutex.MCS.OSQ. <Linux并发与同步专题 (1)原子操作和内存屏障> <Linux并发与同步专题 (2)spinlock> <Linux并发与同步 ...

随机推荐

  1. Python开发——排队问题随机模拟分析

    案例:主要是基于"蒙特卡罗思想",求解排队等待时间问题 场景:厕所排队问题 1.两场电影结束时间相隔较长,互不影响: 2.每场电影结束之后会有20个人想上厕所: 3.这20个人会在 ...

  2. django之模板显示静态文件

    由于django的模板渲染机制,图片不能直接引用,否则不会显示. <img src="/static/img/logo.jpg"> 可以看出图片的大小轮廓,但并不显示内 ...

  3. [HCNA]VLAN配置Hybrid接口

    实验名称 VLAN配置Hybrid接口 日期 2018年4月13日 实验目的 1.掌握配置Hybrid接口的方法. 2.理解Hybrid接口处理Untagged数据帧过程 3.理解Hybrid接口处理 ...

  4. numpy的初探

    # data = numpy.genfromtxt("C:\\Users\\Admin\Desktop\\111.txt", delimiter='\t', dtype='str' ...

  5. git提交项目常用命令及git分支的用法

    1.第一步首先从git托管平台clone项目,我这里就使用idea为例: 填写git的url与存放本地目录名及项目名     2.如果你对项目进行了一些修改,就可以执行git命令,进行提交. 有两种方 ...

  6. Java第8次实验(IO流)

    参考资料 本次作业参考文件 正则表达式参考资料 第1次实验 1. 字符流与文本文件:使用 PrintWriter(写),BufferedReader(读) 参考文件:基础代码目录Student.jav ...

  7. CNN在中文文本分类的应用

    深度学习近一段时间以来在图像处理和NLP任务上都取得了不俗的成绩.通常,图像处理的任务是借助CNN来完成的,其特有的卷积.池化结构能够提取图像中各种不同程度的纹理.结构,并最终结合全连接网络实现信息的 ...

  8. ejabberd为游戏免除注册限制

    ejabberd为游戏免除注册限制 (金庆的专栏 2016.11) ejabberd聊天服务器默认会限制同一IP注册帐号须间隔600s. 在游戏中需要为每个角色注册一个聊天帐号,不应该有此限制. 可以 ...

  9. SOAP Binding: Difference between Document and RPC Style Web Services

    SOAP Binding: Difference between Document and RPC Style Web Services 20FLARES Twitter 1Facebook 9Goo ...

  10. 剑指Offer——中国银行面试知识储备

    剑指Offer--中国银行面试知识储备+面试内容 事件介绍 时间:2016.11.23 08:30 地点:北京市海淀区永丰路299号南门(中国银行软件中心) 事件:中国银行面试(中英文面试) 注意事项 ...