zoukankan      html  css  js  c++  java
  • 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平台上的测试结果相同,好神奇!

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

  • 相关阅读:
    DATASNAP远程方法返回TSTREAM正解
    DELPHI获取宽带IP
    DELPHI HMAC256
    JWT -- JSON WEB TOKEN
    UNIGUI集成HTML导航
    咏南WEB APP开发框架
    购买咏南中间件
    咏南中间件当作WEB SERVER使用方法
    咏南中间件增加WEBSOCKET支持
    iOS -- 设置label的自适应
  • 原文地址:https://www.cnblogs.com/lidabo/p/7374161.html
Copyright © 2011-2022 走看看