前文在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
- #ifndefMy_Event_Header
- #defineMy_Event_Header
- #include<iostream>
- #include<pthread.h>
- #include<errno.h>
- usingnamespacestd;
- //---------------------------------------------------------------
- classCEventImpl
- {
- protected:
- /*
- 动态方式初始化互斥锁,初始化状态变量m_cond
- `bAutoResettrue人工重置
- false自动重置
- */
- CEventImpl(boolmanualReset);
- /*
- 注销互斥锁,注销状态变量m_cond
- */
- ~CEventImpl();
- /*
- 将当前事件对象设置为有信号状态
- 若自动重置,则等待该事件对象的所有线程只有一个可被调度
- 若人工重置,则等待该事件对象的所有线程变为可被调度
- */
- voidSetImpl();
- /*
- 以当前事件对象,阻塞线程,将其永远挂起
- 直到事件对象被设置为有信号状态
- */
- boolWaitImpl();
- /*
- 以当前事件对象,阻塞线程,将其挂起指定时间间隔
- 之后线程自动恢复可调度
- */
- boolWaitImpl(longmilliseconds);
- /*
- 将当前事件对象设置为无信号状态
- */
- voidResetImpl();
- private:
- boolm_manual;
- volatileboolm_state;
- pthread_mutex_tm_mutex;
- pthread_cond_tm_cond;
- };
- inlinevoidCEventImpl::SetImpl()
- {
- if(pthread_mutex_lock(&m_mutex))
- cout<<"cannotsignalevent(lock)"<<endl;
- //设置状态变量为true,对应有信号
- m_state=true;
- //cout<<"CEventImpl::SetImplm_state="<<m_state<<endl;
- //重新激活所有在等待m_cond变量的线程
- if(pthread_cond_broadcast(&m_cond))
- {
- pthread_mutex_unlock(&m_mutex);
- cout<<"cannotsignalevent"<<endl;
- }
- pthread_mutex_unlock(&m_mutex);
- }
- inlinevoidCEventImpl::ResetImpl()
- {
- if(pthread_mutex_lock(&m_mutex))
- cout<<"cannotresetevent"<<endl;
- //设置状态变量为false,对应无信号
- m_state=false;
- //cout<<"CEventImpl::ResetImplm_state="<<m_state<<endl;
- pthread_mutex_unlock(&m_mutex);
- }
- //---------------------------------------------------------------
- classCMyEvent:privateCEventImpl
- {
- public:
- CMyEvent(boolbManualReset=true);
- ~CMyEvent();
- voidSet();
- boolWait();
- boolWait(longmilliseconds);
- boolTryWait(longmilliseconds);
- voidReset();
- private:
- CMyEvent(constCMyEvent&);
- CMyEvent&operator=(constCMyEvent&);
- };
- inlinevoidCMyEvent::Set()
- {
- SetImpl();
- }
- inlineboolCMyEvent::Wait()
- {
- returnWaitImpl();
- }
- inlineboolCMyEvent::Wait(longmilliseconds)
- {
- if(!WaitImpl(milliseconds))
- {
- cout<<"timeout"<<endl;
- returnfalse;
- }
- else
- {
- returntrue;
- }
- }
- inlineboolCMyEvent::TryWait(longmilliseconds)
- {
- returnWaitImpl(milliseconds);
- }
- inlinevoidCMyEvent::Reset()
- {
- ResetImpl();
- }
- #endif
MyEvent.cpp
- #include"MyEvent.h"
- #include<sys/time.h>
- CEventImpl::CEventImpl(boolmanualReset):m_manual(manualReset),m_state(false)
- {
- if(pthread_mutex_init(&m_mutex,NULL))
- cout<<"cannotcreateevent(mutex)"<<endl;
- if(pthread_cond_init(&m_cond,NULL))
- cout<<"cannotcreateevent(condition)"<<endl;
- }
- CEventImpl::~CEventImpl()
- {
- pthread_cond_destroy(&m_cond);
- pthread_mutex_destroy(&m_mutex);
- }
- boolCEventImpl::WaitImpl()
- {
- if(pthread_mutex_lock(&m_mutex))
- {
- cout<<"waitforeventfailed(lock)"<<endl;
- returnfalse;
- }
- while(!m_state)
- {
- //cout<<"CEventImpl::WaitImplwhilem_state="<<m_state<<endl;
- //对互斥体进行原子的解锁工作,然后等待状态信号
- if(pthread_cond_wait(&m_cond,&m_mutex))
- {
- pthread_mutex_unlock(&m_mutex);
- cout<<"waitforeventfailed"<<endl;
- returnfalse;
- }
- }
- if(m_manual)
- m_state=false;
- pthread_mutex_unlock(&m_mutex);
- //cout<<"CEventImpl::WaitImplendm_state="<<m_state<<endl;
- returntrue;
- }
- boolCEventImpl::WaitImpl(longmilliseconds)
- {
- intrc=0;
- structtimespecabstime;
- structtimevaltv;
- 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<<"waitforeventfailed(lock)"<<endl;
- returnfalse;
- }
- 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<<"cannotwaitforevent"<<endl;
- returnfalse;
- }
- }
- if(rc==0&&m_manual)
- m_state=false;
- pthread_mutex_unlock(&m_mutex);
- returnrc==0;
- }
- CMyEvent::CMyEvent(boolbManualReset):CEventImpl(bManualReset)
- {
- }
- CMyEvent::~CMyEvent()
- {
- }
下边是测试代码
- //pthread_event.cpp:定义控制台应用程序的入口点。
- //
- #include<unistd.h>
- #include"MyEvent.h"
- #definePRINT_TIMES10
- //创建一个人工自动重置事件对象
- CMyEventg_myEvent;
- intg_iNum=0;
- //线程函数1
- void*ThreadProc1(void*pParam)
- {
- for(inti=0;i<PRINT_TIMES;i++)
- {
- g_iNum++;
- cout<<"ThreadProc1doprint,Num="<<g_iNum<<endl;
- //设置事件为有信号状态
- g_myEvent.Set();
- sleep(1);
- }
- return(void*)0;
- }
- //线程函数2
- void*ThreadProc2(void*pParam)
- {
- boolbRet=false;
- while(1)
- {
- if(g_iNum>=PRINT_TIMES)
- {
- break;
- }
- //以当前事件对象阻塞本线程,将其挂起
- bRet=g_myEvent.Wait();
- if(bRet)
- {
- cout<<"ThreadProc2doprint,Num="<<g_iNum<<endl;
- //设置事件为无信号状态
- g_myEvent.Reset();
- }
- else
- {
- cout<<"ThreadProc2systemexception"<<endl;
- }
- }
- return(void*)0;
- }
- intmain(intargc,char*argv[])
- {
- pthread_tthread1,thread2;
- pthread_attr_tattr1,attr2;
- //创建两个工作线程
- pthread_attr_init(&attr1);
- pthread_attr_setdetachstate(&attr1,PTHREAD_CREATE_JOINABLE);
- if(pthread_create(&thread1,&attr1,ThreadProc1,NULL)==-1)
- {
- cout<<"Thread1:createfailed"<<endl;
- }
- pthread_attr_init(&attr2);
- pthread_attr_setdetachstate(&attr2,PTHREAD_CREATE_JOINABLE);
- if(pthread_create(&thread2,&attr2,ThreadProc2,NULL)==-1)
- {
- cout<<"Thread2:createfailed"<<endl;
- }
- //等待线程结束
- void*result;
- pthread_join(thread1,&result);
- pthread_join(thread2,&result);
- //关闭线程,释放资源
- pthread_attr_destroy(&attr1);
- pthread_attr_destroy(&attr2);
- intiWait;
- cin>>iWait;
- return0;
- }
编译,运行。可以看到,与Win32平台上的测试结果相同,好神奇!