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

[cpp] view plain copy
 
  1. #ifndef My_Event_Header  
  2. #define My_Event_Header  
  3.   
  4. #include <iostream>  
  5. #include <pthread.h>  
  6. #include <errno.h>  
  7.   
  8. using namespace std;  
  9.   
  10. //---------------------------------------------------------------  
  11.   
  12. class CEventImpl  
  13. {  
  14. protected:  
  15.       
  16.     /* 
  17.      动态方式初始化互斥锁,初始化状态变量m_cond 
  18.     `bAutoReset  true   人工重置 
  19.                  false  自动重置 
  20.     */  
  21.     CEventImpl(bool manualReset);         
  22.       
  23.     /* 
  24.      注销互斥锁,注销状态变量m_cond 
  25.     */  
  26.     ~CEventImpl();  
  27.   
  28.     /* 
  29.      将当前事件对象设置为有信号状态 
  30.      若自动重置,则等待该事件对象的所有线程只有一个可被调度 
  31.      若人工重置,则等待该事件对象的所有线程变为可被调度 
  32.     */  
  33.     void SetImpl();  
  34.   
  35.     /* 
  36.      以当前事件对象,阻塞线程,将其永远挂起 
  37.      直到事件对象被设置为有信号状态 
  38.     */  
  39.     bool WaitImpl();  
  40.   
  41.     /* 
  42.      以当前事件对象,阻塞线程,将其挂起指定时间间隔 
  43.      之后线程自动恢复可调度 
  44.     */  
  45.     bool WaitImpl(long milliseconds);  
  46.   
  47.     /* 
  48.      将当前事件对象设置为无信号状态 
  49.     */  
  50.     void ResetImpl();  
  51.   
  52. private:  
  53.     bool            m_manual;  
  54.     volatile bool   m_state;  
  55.     pthread_mutex_t m_mutex;  
  56.     pthread_cond_t  m_cond;  
  57. };  
  58.   
  59. inline void CEventImpl::SetImpl()  
  60. {  
  61.     if (pthread_mutex_lock(&m_mutex))     
  62.         cout<<"cannot signal event (lock)"<<endl;  
  63.   
  64.     //设置状态变量为true,对应有信号  
  65.     m_state = true;  
  66.   
  67.     //cout<<"CEventImpl::SetImpl m_state = "<<m_state<<endl;  
  68.   
  69.     //重新激活所有在等待m_cond变量的线程  
  70.     if (pthread_cond_broadcast(&m_cond))  
  71.     {  
  72.         pthread_mutex_unlock(&m_mutex);  
  73.         cout<<"cannot signal event"<<endl;  
  74.     }  
  75.     pthread_mutex_unlock(&m_mutex);  
  76. }  
  77.   
  78. inline void CEventImpl::ResetImpl()  
  79. {  
  80.     if (pthread_mutex_lock(&m_mutex))     
  81.         cout<<"cannot reset event"<<endl;  
  82.   
  83.     //设置状态变量为false,对应无信号  
  84.     m_state = false;  
  85.   
  86.     //cout<<"CEventImpl::ResetImpl m_state = "<<m_state<<endl;  
  87.   
  88.     pthread_mutex_unlock(&m_mutex);  
  89. }  
  90.   
  91. //---------------------------------------------------------------  
  92.   
  93. class CMyEvent: private CEventImpl  
  94. {  
  95. public:  
  96.     CMyEvent(bool bManualReset = true);  
  97.     ~CMyEvent();  
  98.   
  99.     void Set();  
  100.     bool Wait();  
  101.     bool Wait(long milliseconds);  
  102.     bool TryWait(long milliseconds);  
  103.     void Reset();  
  104.   
  105. private:  
  106.     CMyEvent(const CMyEvent&);  
  107.     CMyEvent& operator = (const CMyEvent&);  
  108. };  
  109.   
  110.   
  111. inline void CMyEvent::Set()  
  112. {  
  113.     SetImpl();  
  114. }  
  115.   
  116. inline bool CMyEvent::Wait()  
  117. {  
  118.     return WaitImpl();  
  119. }  
  120.   
  121. inline bool CMyEvent::Wait(long milliseconds)  
  122. {  
  123.     if (!WaitImpl(milliseconds))  
  124.     {  
  125.         cout<<"time out"<<endl;  
  126.         return false;  
  127.     }  
  128.     else  
  129.     {  
  130.         return true;  
  131.     }  
  132. }  
  133.   
  134. inline bool CMyEvent::TryWait(long milliseconds)  
  135. {  
  136.     return WaitImpl(milliseconds);  
  137. }  
  138.   
  139. inline void CMyEvent::Reset()  
  140. {  
  141.     ResetImpl();  
  142. }  
  143.   
  144. #endif  


MyEvent.cpp

[cpp] view plain copy
 
  1. #include "MyEvent.h"  
  2. #include <sys/time.h>  
  3.   
  4. CEventImpl::CEventImpl(bool manualReset): m_manual(manualReset), m_state(false)  
  5. {  
  6.     if (pthread_mutex_init(&m_mutex, NULL))  
  7.         cout<<"cannot create event (mutex)"<<endl;  
  8.     if (pthread_cond_init(&m_cond, NULL))  
  9.         cout<<"cannot create event (condition)"<<endl;  
  10. }  
  11.   
  12. CEventImpl::~CEventImpl()  
  13. {  
  14.     pthread_cond_destroy(&m_cond);  
  15.     pthread_mutex_destroy(&m_mutex);  
  16. }  
  17.   
  18. bool CEventImpl::WaitImpl()  
  19. {  
  20.     if (pthread_mutex_lock(&m_mutex))  
  21.     {  
  22.         cout<<"wait for event failed (lock)"<<endl;   
  23.         return false;  
  24.     }  
  25.     while (!m_state)   
  26.     {  
  27.         //cout<<"CEventImpl::WaitImpl while m_state = "<<m_state<<endl;  
  28.   
  29.         //对互斥体进行原子的解锁工作,然后等待状态信号  
  30.         if (pthread_cond_wait(&m_cond, &m_mutex))  
  31.         {  
  32.             pthread_mutex_unlock(&m_mutex);  
  33.             cout<<"wait for event failed"<<endl;  
  34.             return false;  
  35.         }  
  36.     }  
  37.     if (m_manual)  
  38.         m_state = false;  
  39.     pthread_mutex_unlock(&m_mutex);  
  40.   
  41.     //cout<<"CEventImpl::WaitImpl end m_state = "<<m_state<<endl;  
  42.   
  43.     return true;  
  44. }  
  45.   
  46. bool CEventImpl::WaitImpl(long milliseconds)  
  47. {  
  48.     int rc = 0;  
  49.     struct timespec abstime;  
  50.     struct timeval tv;  
  51.     gettimeofday(&tv, NULL);  
  52.     abstime.tv_sec  = tv.tv_sec + milliseconds / 1000;  
  53.     abstime.tv_nsec = tv.tv_usec*1000 + (milliseconds % 1000)*1000000;  
  54.     if (abstime.tv_nsec >= 1000000000)  
  55.     {  
  56.         abstime.tv_nsec -= 1000000000;  
  57.         abstime.tv_sec++;  
  58.     }  
  59.   
  60.     if (pthread_mutex_lock(&m_mutex) != 0)  
  61.     {  
  62.         cout<<"wait for event failed (lock)"<<endl;   
  63.         return false;  
  64.     }  
  65.     while (!m_state)   
  66.     {  
  67.         //自动释放互斥体并且等待m_cond状态,并且限制了最大的等待时间  
  68.         if ((rc = pthread_cond_timedwait(&m_cond, &m_mutex, &abstime)))  
  69.         {  
  70.             if (rc == ETIMEDOUT) break;  
  71.             pthread_mutex_unlock(&m_mutex);  
  72.             cout<<"cannot wait for event"<<endl;  
  73.             return false;  
  74.         }  
  75.     }  
  76.     if (rc == 0 && m_manual)   
  77.         m_state = false;  
  78.     pthread_mutex_unlock(&m_mutex);  
  79.     return rc == 0;  
  80. }  
  81.   
  82. CMyEvent::CMyEvent(bool bManualReset): CEventImpl(bManualReset)  
  83. {  
  84. }  
  85.   
  86. CMyEvent::~CMyEvent()  
  87. {  
  88. }  


    下边是测试代码

[cpp] view plain copy
 
  1. // pthread_event.cpp : 定义控制台应用程序的入口点。  
  2. //  
  3.   
  4. #include <unistd.h>  
  5. #include "MyEvent.h"  
  6.   
  7. #define PRINT_TIMES 10  
  8.   
  9. //创建一个人工自动重置事件对象  
  10. CMyEvent g_myEvent;  
  11. int g_iNum = 0;  
  12.   
  13.   
  14. //线程函数1  
  15. void * ThreadProc1(void *pParam)  
  16. {  
  17.     for (int i = 0; i < PRINT_TIMES; i++)  
  18.     {  
  19.         g_iNum++;  
  20.         cout<<"ThreadProc1 do print, Num = "<<g_iNum<<endl;  
  21.   
  22.         //设置事件为有信号状态  
  23.         g_myEvent.Set();  
  24.   
  25.         sleep(1);  
  26.     }  
  27.   
  28.     return (void *)0;  
  29. }  
  30.   
  31. //线程函数2  
  32. void * ThreadProc2(void *pParam)  
  33. {  
  34.     bool bRet = false;  
  35.     while ( 1 )  
  36.     {  
  37.         if ( g_iNum >= PRINT_TIMES )  
  38.         {  
  39.             break;  
  40.         }  
  41.   
  42.         //以当前事件对象阻塞本线程,将其挂起  
  43.         bRet = g_myEvent.Wait();  
  44.         if ( bRet )  
  45.         {  
  46.             cout<<"ThreadProc2 do print, Num = "<<g_iNum<<endl;  
  47.   
  48.             //设置事件为无信号状态  
  49.             g_myEvent.Reset();  
  50.         }  
  51.         else  
  52.         {  
  53.             cout<<"ThreadProc2 system exception"<<endl;  
  54.         }  
  55.     }  
  56.   
  57.     return (void *)0;  
  58. }  
  59.   
  60.   
  61. int main(int argc, char* argv[])  
  62. {  
  63.     pthread_t thread1,thread2;  
  64.     pthread_attr_t attr1,attr2;  
  65.   
  66.   
  67.     //创建两个工作线程  
  68.     pthread_attr_init(&attr1);  
  69.     pthread_attr_setdetachstate(&attr1,PTHREAD_CREATE_JOINABLE);  
  70.     if (pthread_create(&thread1,&attr1, ThreadProc1,NULL) == -1)  
  71.     {  
  72.         cout<<"Thread 1: create failed"<<endl;  
  73.     }  
  74.     pthread_attr_init(&attr2);  
  75.     pthread_attr_setdetachstate(&attr2,PTHREAD_CREATE_JOINABLE);  
  76.     if (pthread_create(&thread2,&attr2, ThreadProc2,NULL) == -1)  
  77.     {  
  78.         cout<<"Thread 2: create failed"<<endl;  
  79.     }  
  80.   
  81.     //等待线程结束  
  82.     void *result;  
  83.     pthread_join(thread1,&result);  
  84.     pthread_join(thread2,&result);  
  85.   
  86.     //关闭线程,释放资源  
  87.     pthread_attr_destroy(&attr1);  
  88.     pthread_attr_destroy(&attr2);  
  89.   
  90.     int iWait;  
  91.     cin>>iWait;  
  92.   
  93.     return 0;  
  94. }  


    编译,运行。可以看到,与Win32平台上的测试结果相同,好神奇!

Linux平台用C++实现事件对象,同步线程

from:http://blog.csdn.net/chexlong/article/details/7080537 

上一篇:阿里云机器学习平台PAI使用简明教程(二)


下一篇:手机网站和PC网站兼容的响应式网页设计