c++ 封装线程库 1
1.Pthread条件变量简介
条件变量也是线程间同步一个重要的内容,如果说互斥是一个种竞争关系,那么条件变量用于协调线程之间的关系,是一种合作关系。
条件变量的应用很多,例如:BlockingQueue,ThreadPool等。
2. 条件变量的封装
其实就是对pthread_cond_t和相关函数的封装:
#include <pthread.h> pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//静态初始化 int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);//动态初始化 int pthread_cond_signal(pthread_cond_t *cond); int pthread_cond_broadcast(pthread_cond_t *cond); int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime); int pthread_cond_destroy(pthread_cond_t *cond);
另外,我们在调用pthread_cond_wait的时候,必须先加锁,需要用到之前MutexLock的私用成员函数,这里已经在MutexLock.h中将class Condition设定为了MutexLock的一个友元。
//Condition.h #ifndef __CONDITION_H__
#define __CONDITION_H__
#include "MutexLock.h"
#include <pthread.h>
#include <boost/noncopyable.hpp>
#include <assert.h>
class MutexLock;
class Condition
{
public:
Condition(MutexLock &mutex);
~Condition();
void wait();//封装pthread_cond_wait
void notify();//封装pthread_cond_signal
void notifyAll();//封装pthread_cond_broadcast
private:
pthread_cond_t cond_;
MutexLock &mutex_;
};
#endi#include "Condition.#include "MutexLock.h"#include <assert.h>
Condition::Condition(MutexLock &mutex):mutex_(mutex)
{
CHECK(!pthread_cond_init(&cond_, NULL));//条件变量初始化
} Condition::~Condition()
{
CHECK(!pthread_cond_destroy(&cond_));//析构操作
}
void Condition::wait()
{
assert(mutex_.isLocking());//wait前必须上锁 assert函数就是用来调试的 assert(exp) 若exp的表达式为假 则程序不执行结束报错 为真则什么也不做!!
CHECK(!pthread_cond_wait(&cond_, mutex_.getMutexPtr()));
//pthread_cond_wait 阻塞时释放锁,返回时会自动加锁
mutex_.restoreMutexStatus(); //还原状态
}
void Condition::notify()
{
CHECK(!pthread_cond_signal(&cond_));//通知等待线程队列中的线程
} void Condition::notifyAll()
{
CHECK(!pthread_cond_broadcast(&cond_));//通知所有等待线程
}
注意学习下知识点:!!!
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
等待条件有两种方式:无条件等待pthread_cond_wait()和计时等待pthread_cond_timedwait(),其中计时等待方式如果在给定时刻前条件没有满足,则返回ETIMEOUT,结束等待,
其中abstime以与time()系统调用相同意义的绝对时间形式出现,0表示格林尼治时间1970年1月1日0时0分0秒。
无论哪种等待方式,都必须和一个互斥锁配合,以防止多个线程同时请求pthread_cond_wait()(或pthread_cond_timedwait(),下同)的竞争条件(Race Condition)。
mutex互斥锁必须是普通锁(PTHREAD_MUTEX_TIMED_NP)或者适应锁(PTHREAD_MUTEX_ADAPTIVE_NP),且在调用pthread_cond_wait()前必须由本线程加锁(pthread_mutex_lock()),
而在更新条件等待队列以前,mutex保持锁定状态,并在线程挂起进入等待前解锁。
在条件满足从而离开pthread_cond_wait()之前,mutex将被重新加锁,以与进入pthread_cond_wait()前的加锁动作对应。
激发条件有两种形式,pthread_cond_signal()激活一个等待该条件的线程,存在多个等待线程时按入队顺序激活其中一个; 而pthread_cond_broadcast()则激活所有等待线程。
=========================================================
在网上看到一个名词“惊群效应”,意思就是说broadcast使用不当,当唤醒所有线程而只有一个线程能够拿到资源,所以关于broadcast还是要慎用。
关于封装条件变量的一般使用,假设我们要实现简单的容量无限的BlockingQueue,可以这样写: BlockingQueue就是阻塞队列 经典到就是生产者消费者模型的实现
MutexLock mutex;
Condition cond(mutex);
std::deque<int> queue; int dequeue()//出列
{
MutexLockGurad lock(mutex);
while(queue.empty())
{
cond.wait();//这一步会释放mutex并进入等待,这两个操作是原子的
//wait()返回后,会自动重新加锁 这个wait就是condition类中封装的 pthread_cond_wait函数
}
assert(!queue.empty());
int top = queue.front();
queue.pop_front();
return top;
} void enqueue(int x )//入队
{
MutexLockGurad(mutex);
queue.push_back(x);
cond.notify();//这句也可以移出临界区 ??????不是特别明白
}
c++ 封装线程库 1的更多相关文章
- c++ 封装线程库 2
1.2线程回收: 首先得知道线程的两个状态: Joinable Detached 简单理解,如果一个线程是joinable的状态,那么这样的线程,就必须使用pthread_join来回收,否则程序结束 ...
- c++ 封装线程库 3
1. 继承与重写run方法 我们封装了Thread类,并设置成员函数run()为纯虚函数,因此我们使用类继承,并重写run方法: class IncCount : public Thread//增加计 ...
- c++ 封装线程库 0
1.互斥锁简介 互斥锁主要用于互斥,互斥是一种竞争关系,用来保护临界资源一次只被一个线程访问. POSIX Pthread提供下面函数用来操作互斥锁. int pthread_mutex_init(p ...
- Linux posix线程库总结
由于历史原因,2.5.x以前的linux对pthreads没有提供内核级的支持,所以在linux上的pthreads实现只能采用n:1的方式,也称为库实现. 线程的实现,经历了如下发展阶段: Linu ...
- 引擎之旅 Chapter.2 线程库
预备知识可参考我整理的博客 Windows编程之线程:https://www.cnblogs.com/ZhuSenlin/p/16662075.html Windows编程之线程同步:https:// ...
- 【Jetlang】一个高性能的Java线程库
actor Jetlang 提供了一个高性能的Java线程库,该库是 JDK 1.5 中的 java.util.concurrent 包的补充,可用于基于并发消息机制的应用. .net的MS CCR ...
- Boost线程库学习笔记
一.创建一个线程 创建线程 boost::thread myThread(threadFun); 需要注意的是:参数可以是函数对象或者函数指针.并且这个函数无参数,并返回void类型. 当一个thre ...
- 【Node.js 自己封装的库 http_parse, libuv】
[Node.js 自己封装的库 http_parse, libuv] Node.js 介绍:一个网络框架,更多:http://www.oschina.net/p/nodejs 官网:http://no ...
- Arduino线程库ProtoThreads
参考: Arduino线程库ProtoThreads 一个“蝇量级” C 语言协程库
随机推荐
- java中的全局变量与静态变量的区别与联系?有时候为什么专门定义静态变量。(标题党~~)
static代表“每个类一个”而不是“每个对象一个”.即静态变量是类的所有对象共有的. 1 static JFrame f; static MyDrawPanel ml; 整个应用程序如下: 定义在p ...
- Luogu 4409 [ZJOI2006]皇帝的烦恼
BZOJ 1863 lyd口中的夹B递推. 挺妙的解法. 第一个感觉是找到一个最大的相邻的$a_i + a_{i - 1}$就可以了,但是这个想法大概只对了一半,一半的意思是说只有在$n$为偶数的时候 ...
- 红帽企业版RHEL7.1在研域工控板上,开机没有登陆窗口 -- 编写xorg.conf 简单三行解决Ubuntu分辩率不可调的问题
红帽企业版RHEL7.1在研域工控板上,开机没有登陆窗口 没有登陆窗口 的原因分析: 没有登陆窗口的原因是因为有多个屏幕在工作,其中一个就是build-in 屏幕(内置的虚拟屏幕)和外接的显示器,并且 ...
- 第四章输入/输出(I/O)4.2PCL中I/O模块及类介绍
PCL中I/O库提供了点云文件输入输出相关的操作类,并封装了OpenNI兼容的设备源数据获取接口,可直接从众多感知设备获取点云图像等数据.I/O模块利用21个类和28个函数实现了对点云的获取.读入.存 ...
- Entity Framework Tutorial Basics(10):Entity Lifecycle
Entity Lifecycle: Before we work on CRUD operation (Create, Read, Update, Delete), it's important to ...
- STL-- vector中resize()和reserve()区别
最近写了一个小型的STL--TinySTL.发现有一些基础的东西需要记录下来,所以我打算多写一些东西,方便以后查看. 先看看<C++ Primer>中对resize()函数两种用法的介绍: ...
- JQuery UI Draggable插件使用说明文档
JQuery UI Draggable插件用来使选中的元素可以通过鼠标拖动.Draggable的元素受css: ui-draggable影响, 拖动过程中的css: ui-draggable-drag ...
- linux文件字符集转换(utf8-gb2312)
一,命令行 在LINUX上进行编码转换时,可以利用iconv命令实现,这是针对文件的,即将指定文件从一种编码转换为另一种编码. iconv命令用法如下:iconv [选项...] [文件...] 1. ...
- C# 顺序表---增删改查--逆至--删除最小值
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- C# console application executing macro function
C#控制台应用程序,执行或运行Office的宏函数,程序如下: 应用例子: