Linux平台用C++实现事件对象,同步线程
前文在Win32平台上用C++实现了事件对象Event,对线程进行同步,以达到期望目的。这次在Linux平台上实现与之类似的事件对象。与其相关的一组API包括:pthread_mutex_init,pthread_cond_init,pthread_mutex_lock,pthread_cond_wait,pthread_mutex_unlock,pthread_cond_broadcast,pthread_cond_timedwait,pthread_cond_destroy,pthread_mutex_destroy。这些API的说明可以在这里找到:http://www.9linux.com/。下边,是封装的事件对象类,以及测试代码。使用VS2005编辑,在虚拟机 Fedora 13中编译,测试通过。
MyEvent.h
- #ifndef My_Event_Header
- #define My_Event_Header
- #include <iostream>
- #include <pthread.h>
- #include <errno.h>
- using namespace std;
- //---------------------------------------------------------------
- class CEventImpl
- {
- protected:
- /*
- 动态方式初始化互斥锁,初始化状态变量m_cond
- `bAutoReset true 人工重置
- false 自动重置
- */
- CEventImpl(bool manualReset);
- /*
- 注销互斥锁,注销状态变量m_cond
- */
- ~CEventImpl();
- /*
- 将当前事件对象设置为有信号状态
- 若自动重置,则等待该事件对象的所有线程只有一个可被调度
- 若人工重置,则等待该事件对象的所有线程变为可被调度
- */
- void SetImpl();
- /*
- 以当前事件对象,阻塞线程,将其永远挂起
- 直到事件对象被设置为有信号状态
- */
- bool WaitImpl();
- /*
- 以当前事件对象,阻塞线程,将其挂起指定时间间隔
- 之后线程自动恢复可调度
- */
- bool WaitImpl(long milliseconds);
- /*
- 将当前事件对象设置为无信号状态
- */
- void ResetImpl();
- private:
- bool m_manual;
- volatile bool m_state;
- pthread_mutex_t m_mutex;
- pthread_cond_t m_cond;
- };
- inline void CEventImpl::SetImpl()
- {
- if (pthread_mutex_lock(&m_mutex))
- cout<<"cannot signal event (lock)"<<endl;
- //设置状态变量为true,对应有信号
- m_state = true;
- //cout<<"CEventImpl::SetImpl m_state = "<<m_state<<endl;
- //重新激活所有在等待m_cond变量的线程
- if (pthread_cond_broadcast(&m_cond))
- {
- pthread_mutex_unlock(&m_mutex);
- cout<<"cannot signal event"<<endl;
- }
- pthread_mutex_unlock(&m_mutex);
- }
- inline void CEventImpl::ResetImpl()
- {
- if (pthread_mutex_lock(&m_mutex))
- cout<<"cannot reset event"<<endl;
- //设置状态变量为false,对应无信号
- m_state = false;
- //cout<<"CEventImpl::ResetImpl m_state = "<<m_state<<endl;
- pthread_mutex_unlock(&m_mutex);
- }
- //---------------------------------------------------------------
- class CMyEvent: private CEventImpl
- {
- public:
- CMyEvent(bool bManualReset = true);
- ~CMyEvent();
- void Set();
- bool Wait();
- bool Wait(long milliseconds);
- bool TryWait(long milliseconds);
- void Reset();
- private:
- CMyEvent(const CMyEvent&);
- CMyEvent& operator = (const CMyEvent&);
- };
- inline void CMyEvent::Set()
- {
- SetImpl();
- }
- inline bool CMyEvent::Wait()
- {
- return WaitImpl();
- }
- inline bool CMyEvent::Wait(long milliseconds)
- {
- if (!WaitImpl(milliseconds))
- {
- cout<<"time out"<<endl;
- return false;
- }
- else
- {
- return true;
- }
- }
- inline bool CMyEvent::TryWait(long milliseconds)
- {
- return WaitImpl(milliseconds);
- }
- inline void CMyEvent::Reset()
- {
- ResetImpl();
- }
- #endif
MyEvent.cpp
- #include "MyEvent.h"
- #include <sys/time.h>
- CEventImpl::CEventImpl(bool manualReset): m_manual(manualReset), m_state(false)
- {
- if (pthread_mutex_init(&m_mutex, NULL))
- cout<<"cannot create event (mutex)"<<endl;
- if (pthread_cond_init(&m_cond, NULL))
- cout<<"cannot create event (condition)"<<endl;
- }
- CEventImpl::~CEventImpl()
- {
- pthread_cond_destroy(&m_cond);
- pthread_mutex_destroy(&m_mutex);
- }
- bool CEventImpl::WaitImpl()
- {
- if (pthread_mutex_lock(&m_mutex))
- {
- cout<<"wait for event failed (lock)"<<endl;
- return false;
- }
- while (!m_state)
- {
- //cout<<"CEventImpl::WaitImpl while m_state = "<<m_state<<endl;
- //对互斥体进行原子的解锁工作,然后等待状态信号
- if (pthread_cond_wait(&m_cond, &m_mutex))
- {
- pthread_mutex_unlock(&m_mutex);
- cout<<"wait for event failed"<<endl;
- return false;
- }
- }
- if (m_manual)
- m_state = false;
- pthread_mutex_unlock(&m_mutex);
- //cout<<"CEventImpl::WaitImpl end m_state = "<<m_state<<endl;
- return true;
- }
- bool CEventImpl::WaitImpl(long milliseconds)
- {
- int rc = 0;
- struct timespec abstime;
- struct timeval tv;
- gettimeofday(&tv, NULL);
- abstime.tv_sec = tv.tv_sec + milliseconds / 1000;
- abstime.tv_nsec = tv.tv_usec*1000 + (milliseconds % 1000)*1000000;
- if (abstime.tv_nsec >= 1000000000)
- {
- abstime.tv_nsec -= 1000000000;
- abstime.tv_sec++;
- }
- if (pthread_mutex_lock(&m_mutex) != 0)
- {
- cout<<"wait for event failed (lock)"<<endl;
- return false;
- }
- while (!m_state)
- {
- //自动释放互斥体并且等待m_cond状态,并且限制了最大的等待时间
- if ((rc = pthread_cond_timedwait(&m_cond, &m_mutex, &abstime)))
- {
- if (rc == ETIMEDOUT) break;
- pthread_mutex_unlock(&m_mutex);
- cout<<"cannot wait for event"<<endl;
- return false;
- }
- }
- if (rc == 0 && m_manual)
- m_state = false;
- pthread_mutex_unlock(&m_mutex);
- return rc == 0;
- }
- CMyEvent::CMyEvent(bool bManualReset): CEventImpl(bManualReset)
- {
- }
- CMyEvent::~CMyEvent()
- {
- }
下边是测试代码
- // pthread_event.cpp : 定义控制台应用程序的入口点。
- //
- #include <unistd.h>
- #include "MyEvent.h"
- #define PRINT_TIMES 10
- //创建一个人工自动重置事件对象
- CMyEvent g_myEvent;
- int g_iNum = 0;
- //线程函数1
- void * ThreadProc1(void *pParam)
- {
- for (int i = 0; i < PRINT_TIMES; i++)
- {
- g_iNum++;
- cout<<"ThreadProc1 do print, Num = "<<g_iNum<<endl;
- //设置事件为有信号状态
- g_myEvent.Set();
- sleep(1);
- }
- return (void *)0;
- }
- //线程函数2
- void * ThreadProc2(void *pParam)
- {
- bool bRet = false;
- while ( 1 )
- {
- if ( g_iNum >= PRINT_TIMES )
- {
- break;
- }
- //以当前事件对象阻塞本线程,将其挂起
- bRet = g_myEvent.Wait();
- if ( bRet )
- {
- cout<<"ThreadProc2 do print, Num = "<<g_iNum<<endl;
- //设置事件为无信号状态
- g_myEvent.Reset();
- }
- else
- {
- cout<<"ThreadProc2 system exception"<<endl;
- }
- }
- return (void *)0;
- }
- int main(int argc, char* argv[])
- {
- pthread_t thread1,thread2;
- pthread_attr_t attr1,attr2;
- //创建两个工作线程
- pthread_attr_init(&attr1);
- pthread_attr_setdetachstate(&attr1,PTHREAD_CREATE_JOINABLE);
- if (pthread_create(&thread1,&attr1, ThreadProc1,NULL) == -1)
- {
- cout<<"Thread 1: create failed"<<endl;
- }
- pthread_attr_init(&attr2);
- pthread_attr_setdetachstate(&attr2,PTHREAD_CREATE_JOINABLE);
- if (pthread_create(&thread2,&attr2, ThreadProc2,NULL) == -1)
- {
- cout<<"Thread 2: create failed"<<endl;
- }
- //等待线程结束
- void *result;
- pthread_join(thread1,&result);
- pthread_join(thread2,&result);
- //关闭线程,释放资源
- pthread_attr_destroy(&attr1);
- pthread_attr_destroy(&attr2);
- int iWait;
- cin>>iWait;
- return 0;
- }
编译,运行。可以看到,与Win32平台上的测试结果相同,好神奇!
from:http://blog.csdn.net/chexlong/article/details/7080537
Linux平台用C++实现事件对象,同步线程的更多相关文章
- Linux平台用C++实现事件对象,同步线程(转)
本文属于转载,原文链接如下:http://blog.csdn.net/chexlong/article/details/7080537 与其相关的一组API包括:pthread_mutex_init, ...
- [C++] socket - 5 [API事件对象实现线程同步]
/*API事件对象实现线程同步*/ #include<windows.h> #include<stdio.h> DWORD WINAPI myfun1(LPVOID lpPar ...
- 事件同步(一)-——CreateEvent( )事件对象实现线程同步
事件对象分为两类:人工重置事件对象和自动重置事件对象.对于人工重置事件对象,可以同时有多个线程等待到事件对象,成为可调度线程. 对于自动重置事件对象,等待该事件对象的多个线程只能有一个线程成为可调度线 ...
- 转:VC++线程同步-事件对象
这是整理孙鑫VC得到的关于线程同步方面的笔记. n 事件对象也属于内核对象,包含一个使用计数,一个用于指明该事件是一个自动重置的事件还是一个人工重置的事件的布尔值,另一个用于指明该事件处于 ...
- Windows多线程同步系列之三-----事件对象
事件是一个内核事件,内核事件是什么呢,我理解也不深入也不好说,暂且理解为一个内核维护的数据类型吧通过内核事件同步主要 的方法是对事件的信号有和无来进行同步. 比如当我们一个线程进入一段临界代码(独占代 ...
- 第9章 用内核对象进行线程同步(1)_事件对象(Event)
9.1 等待函数 (1)WaitForSingleObject(hObject,dwMilliseonds); ①dwMilliseconds为INFINITE时表示无限等待 ②dwMilliseco ...
- 转:sock_ev——linux平台socket事件框架(socket API的封装) .
把linux平台提供的有关socket操作的API进行封装是有必要的:基于stream操作的流程与基于dgram操作的流程略有不同,分别放在两个类中,但两者又有很多相似的操作,因此写一个基类,让其继承 ...
- Linux 平台静默安装 Oracle客户端
需求:Linux平台,安装完整版Oracle客户端 Tips:如果只是用到sqlldr,sqlplus功能,可以参考<Linux上oracle精简版客户端快速部署>快速部署精简版:如果需要 ...
- 【转】Redis安装整理(window平台和Linux平台)
原文连接:http://zheng12tian.iteye.com/blog/1471726 原文作者:zheng12tian 转载注明以上信息! window平台Redis安装 redis wind ...
随机推荐
- git回滚到指定commit
一次性commit好多文件,push上去之后,发现工程不可用,只能回滚,上网搜索回滚办法,下边这个是自己亲试的,特别好使: 操作步骤: 1.git checkout the_branch 2.git ...
- Azure Cloud Service - PaaS
使用Azure Cloud Service有一段时间了,前阵子在公司内部做一个Cloud Service培训的时候就在想,能不能用一幅图把Cloud Service所涉及的概念都罗列出来.于是就有了下 ...
- 20145202马超 《Java程序设计》第九周学习总结
JDBC 数据库本身是个独立运行的应用程序 撰写应用程序是利用通信协议对数据库进行指令交换,以进行数据的增删查找. JDBC(Java DataBase Connectivity)是Java联机数据库 ...
- [Codeforces Round #443]Div2 C Short Program
给你一串$n$个按顺序的位运算操作(&,|,^),形如"opt x",要求用不超过5行的位运算,按顺序操作出来和那个结果是一样的.$(n<=5e5,0<=x&l ...
- android studio 首字母提示 设置 大小写敏感
在使用Android studo 编写程序时, 刚开始,关键字提示 首字母 设置了 大小写敏感,小写字母只能提示小写字母开头的,大写字母只能提示大写字母开始的,比较麻烦,在网上搜了下,解决办法如下: ...
- 【Support Vector Regression】林轩田机器学习技法
上节课讲了Kernel的技巧如何应用到Logistic Regression中.核心是L2 regularized的error形式的linear model是可以应用Kernel技巧的. 这一节,继续 ...
- Spring+SpringMVC+MyBatis+Redis框架学习笔记
在Java互联网中,以Spring+Spring MVC+MyBatis (SSM) 作为主流框架. SSM+Redis的结构图 在这种框架系统中: Spring IoC 承担了一个资源管理.整合.即 ...
- Vue组件编写
Vue无疑是近来最火的一个前端框架,它吸取了angular1.x和react的精华,性能优良,而且易于上手,本文主要是关于如何去写一个组件. 首先是项目目录 编写组件 在这里我写了一个日期控件(移动端 ...
- Appium与python自动测试环境及demo详解
App--UI自动化这种高端的名词已经被越来越多的人所高呼,可是从实际角度来讲,个人觉得还是有点鸡肋,不如接口自动化敏捷度高,工作量 也是接口自动化的好几倍.但是,[划重点了] 在技术时代中,作为测 ...
- Mysql忘记root密码怎么办?(已解决)
为了写这篇文档,假装一下忘记密码!!!! 首先我数据库是正常的,可以使用. root@localhost:~# mysql -uroot -p mysql> mysql> show dat ...