Linux线程同步之——条件变量
来源:互联网 发布:委托网络国债基金产品 编辑:程序博客网 时间:2024/06/06 14:01
条件变量是线程可用的另一种同步机制。条件变量给多线程提供了一个会合的场所。它主要包括两个动作:一个线程等待“条件变量的条件成立”而挂起;另一个线程使“条件成立”(给出条件成立信号)。条件变量与互斥量一起使用时,允许线程以无竞争的方式等待特定的条件发生。
条件变量本身是互斥量保护的。线程在改变条件状态之前必须首先锁住互斥量。其他线程在获得互斥量之前不会觉察到这种改变,因为互斥量必须在锁定以后才能计算条件。
在使用条件变量之前,必须对它进行初始化。由pthread_cond_t数据类型表示的条件变量可以用两种方式进行初始化,可以把常量PTHREAD_COND_INITIALIZER赋给静态分配的条件变量,但是如果条件变量是动态分配的,则需要使用pthread_cond_init函数对它进行初始化。
在释放条件变量底层的内存空间之前,可以使用pthread_cond_destroy函数对条件变量进行反初始化。
#include <pthread.h>int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);int pthread_cond_destroy(pthread_cond_t *cond);两个函数的返回值:若成功,返回0;否则,返回错误编号通常情况下,pthread_cond_init函数的attr参数设置为NULL。
我们使用pthread_cond_wait等待条件变量变为真。pthread_cond_wait函数与pthread_cond_wait函数相似,只是多了一个超时。超时值指定我们愿意等待多长的时间,它通过timespace结构指定,这个时间值是一个绝对数而不是相对数。如果超时到期时条件还是没有出现,pthread_coond_timewait将重新获取互斥量,然后返回错误ETIMEOUT。
#include <pthread.h>int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct timespace *restrict tsptr);两个函数的返回值:若成功,返回0;否则,返回错误编号
有两个函数可以用于通知线程条件已经满足。pthread_cond_signal函数至少能唤醒一个等待该条件的线程,而pthread_cond_broadcast函数则能唤醒等待该条件的所有线程。
#include <pthread.h>int pthread_cond_signal(pthread_cont_t *cond);int pthread_cond_broadcast(pthread_cond_t *cond);两个函数的返回值:若成功,返回0;否则,返回错误编号
下面,举一个在“线程池”中经常用到的任务队列,当我们将一个任务放入到任务队列的时候,可以通过条件变量告知等待线程,已经有新任务,可以来取任务执行或当某一线程需要取从任务队列取任务时候,如果任务队列为空,则线程挂起等待条件变量变为真。
文件Mutext.h
#ifndef __MUTEX_H__#define __MUTEX_H__#include <pthread.h>namespace taskqueue{class CMutexLock{public:explicit CMutexLock(){pthread_mutex_init(&m_Mutex, NULL);}~CMutexLock(){pthread_mutex_destroy(&m_Mutex);}void lock(){pthread_mutex_lock(&m_Mutex);}void unlock(){pthread_mutex_unlock(&m_Mutex);}pthread_mutex_t *get(){return &m_Mutex;}private:friend class CCondition;pthread_mutex_t m_Mutex;};class CMutexLockPart{public:explicit CMutexLockPart(CMutexLock &MutexLock):m_MutexLock(MutexLock){m_MutexLock.lock();}~CMutexLockPart(){m_MutexLock.unlock();}private:CMutexLock &m_MutexLock;};}#endif//#ifndef __MUTEX_H__文件Condition.h
#ifndef __CONDITION_H__ #define __CONDITION_H__ #include "Mutex.h" #include <time.h>class CCondition { public: explicit CCondition(CMutexLock &MutexLock):m_MutexLock(MutexLock) { ::pthread_cond_init(&m_Condition, NULL);} ~CCondition() { ::pthread_cond_destroy(&m_Condition); } void wait() { ::pthread_cond_wait(&m_Condition, m_MutexLock.get()); } bool waitForSeconds(int iSeconds){struct timespec abstime;::clock_gettime(CLOCK_REALTIME, &abstime);abstime.tv_sec += static_cast<time_t>(iSeconds);return ETIMEDOUT == ::pthread_cond_timedwait(&m_Condition, m_MutexLock.get(), &abstime);}void signal() { ::pthread_cond_signal(&m_Condition);} void broadcast() { ::pthread_cond_broadcast(&m_Condition); } private: CMutexLock &m_MutexLock; pthread_cond_t m_Condition; };#endif//#ifndef __CONDITION_H__文件TaskQueue.h
#ifndef __TASK_QUEUE_H__#define __TASK_QUEUE_H__#include <queue>#include "Mutex.h"#include "Condition.h"namespace taskqueue{using namespace std;template<typename T>class CTaskQueue{public:explicit CTaskQueue():m_MutexLock(),m_NotEmpty(m_MutexLock),m_queue(){}~CTaskQueue(){}void PutTask(const T &task){CMutexLockPart PartLock(m_MutexLock);m_queue.push(task);m_NotEmpty.signal();//֪ͨÏ̱߳íʾÓÐÈÎÎñ¿ÉÖ´ÐÐ}T GetTask(){CMutexLockPart PartLock(m_MutexLock);if (m_queue.empty()){m_NotEmpty.wait();//ÈÎÎñ¶ÓÁÐΪ¿Õ£¬ÄÇô¾Í¹ÒÆðµÈ´ý}T RetTask = m_queue.front();m_queue.pop();return RetTask;}private:CMutexLock m_MutexLock;CCondition m_NotEmpty;queue<T> m_queue;};}#endif//#ifndef __TASK_QUEUE_H__下面为具体的测试代码,该测试代码创建了2个线程,第一个线程负责每2秒向任务队列里面放任务,总共放5个任务;第二个线程负责从任务队列里取任务,并执行任务,共取5次。
#include <iostream>#include <unistd.h>#include <pthread.h>#include "TaskQueue.h"using namespace std;using namespace taskqueue;static int g_iGetTaskCount;typedef void(*TaskFunc)(void);void Task(void){g_iGetTaskCount++;cout << "Task Count: " << g_iGetTaskCount << endl;}void *FuncPutTask(void *pArg){CTaskQueue<TaskFunc> *pTaskQueue = static_cast<CTaskQueue<TaskFunc> *>(pArg);for (int i = 0; i < 5; i++){pTaskQueue->PutTask(Task);sleep(2);}pthread_exit((void *)1);}void *FuncGetTask(void *pArg){CTaskQueue<TaskFunc> *pTaskQueue = static_cast<CTaskQueue<TaskFunc> *>(pArg);TaskFunc Task;for (int i = 0; i < 5; i++){Task = pTaskQueue->GetTask();Task();}pthread_exit((void *)2);}/*在多线程编程中,我们经常用到"线程池",在线程池中我们经常使用任务队列。 * 我们的例子展示的是条件变量的一种使用方式:当我们将一个任务放入到任务队 *列的时候通过条件变量告知挂起线程;在取任务队列时候,如果任务队列为空 * 那么就等待任务的到来。 */int main(void){int iRet;pthread_t ThreadPutTaskId;pthread_t ThreadGetTaskId;CTaskQueue<TaskFunc> TaskQueue;iRet = pthread_create(&ThreadPutTaskId, NULL, FuncPutTask, &TaskQueue);if (iRet != 0){cout << "pthread_create:FuncPutTask false!" << endl;return -1;}iRet = pthread_create(&ThreadGetTaskId, NULL, FuncGetTask, &TaskQueue);if (iRet != 0){cout << "pthread_create:FuncGetTask false!" << endl;return -1;}pthread_join(ThreadPutTaskId, NULL);pthread_join(ThreadGetTaskId, NULL);return 0;}我们运行之后的效果为每2秒打印如下所示:
Task Count: 1Task Count: 2Task Count: 3Task Count: 4Task Count: 5
- Linux线程同步之——条件变量
- linux线程同步——条件变量
- Linux线程同步之条件变量
- Linux线程同步之条件变量
- Linux线程同步之条件变量
- Linux线程同步之条件变量
- Linux线程同步之条件变量
- linux 线程同步之条件变量
- Linux线程同步之条件变量
- Linux线程同步之条件变量
- linux线程同步之条件变量
- Linux线程同步之条件变量
- Linux线程同步之条件变量
- Linux下线程同步对象(3)——条件变量
- Linux下线程同步对象(3)——条件变量
- Linux 线程同步---条件变量
- Linux 线程同步---条件变量
- Linux 线程同步---条件变量
- python基础-生成器
- HDU 1010 Tempter of the Bone
- 考研英语近义词与反义词·十三
- JAVA多线程之——CyclicBarrier
- ubuntu下安装ifstat工具来查看网卡上的流量信息
- Linux线程同步之——条件变量
- lstm的数学推导
- 几个小问题
- Python 简介
- 遗传算法
- VMWare8.0 U盘插入不支持的问题解决:
- python总结
- 访问修饰符
- Java多线程——关键字synchronized