Linux平台用C++实现信号量,同步线程

Linux平台用C++实现信号量,同步线程


    使用Linux平台上现有的信号量sem_t相关的一组API,可以方便地进行线程同步。现在用pthread_mutex_t和pthread_cond_t相关的一组API实现信号量机制。这组API包括:pthread_mutex_init,pthread_cond_init,pthread_mutex_lock,pthread_cond_signal,pthread_mutex_unlock,pthread_cond_wait,pthread_cond_timedwait,pthread_cond_destroy和pthread_mutex_destroy,可以在http://www.9linux.com找到各API的说明。下边,是封装的信号量类,以及测试代码。使用VS2005编辑,在虚拟机 Fedora 13中编译,测试通过。

MySemaphore.h

[cpp]  view plain  copy
  1. #ifndef Semaphore_Header  
  2. #define Semaphore_Header  
  3.   
  4. #include <iostream>  
  5. #include <pthread.h>  
  6. #include <errno.h>  
  7. #include <assert.h>  
  8.   
  9. using namespace std;  
  10.   
  11. //------------------------------------------------------------------------  
  12.   
  13. class CSemaphoreImpl  
  14. {  
  15. protected:  
  16.     CSemaphoreImpl(int n, int max);       
  17.     ~CSemaphoreImpl();  
  18.     void SetImpl();  
  19.     void WaitImpl();  
  20.     bool WaitImpl(long lMilliseconds);  
  21.   
  22. private:  
  23.     volatile int    m_n;  
  24.     int             m_max;  
  25.     pthread_mutex_t m_mutex;  
  26.     pthread_cond_t  m_cond;  
  27. };  
  28.   
  29. inline void CSemaphoreImpl::SetImpl()  
  30. {  
  31.     if (pthread_mutex_lock(&m_mutex))     
  32.         cout<<"cannot signal semaphore (lock)"<<endl;  
  33.     if (m_n < m_max)  
  34.     {  
  35.         ++m_n;  
  36.     }  
  37.     else  
  38.     {  
  39.         pthread_mutex_unlock(&m_mutex);  
  40.         cout<<"cannot signal semaphore: count would exceed maximum"<<" m_n = "<<m_n<<"m_max = "<<m_max<<endl;  
  41.     }  
  42.     //重新开始等待m_cond的线程,可被调度  
  43.     if (pthread_cond_signal(&m_cond))  
  44.     {  
  45.         pthread_mutex_unlock(&m_mutex);  
  46.         cout<<"cannot signal semaphore"<<endl;  
  47.     }  
  48.     pthread_mutex_unlock(&m_mutex);  
  49. }  
  50.   
  51. //------------------------------------------------------------------------  
  52.   
  53. /* 
  54.  
  55.  信号量同步机制 
  56.  信号量提供一个计数值,可以进行原子操作。V 将计数值加1,使得 
  57.  等待该信号量的线程可以被调用(调用Set()),P 将计数值减1,使 
  58.  当前线程被挂起,进行睡眠(调用Wait())。 
  59.  当信号量的计数值被初始化为0时,调用P操作,将挂起当前线程。 
  60.  当信号量被激活,即调用V操作后,被挂起的线程就有机会被重新调度了。 
  61.  
  62. */  
  63.   
  64. class CMySemaphore: private CSemaphoreImpl  
  65. {  
  66. public:  
  67.   
  68.     /* 
  69.      创建一个信号量,信号量计数值当前值为参数n,最大值为max。 
  70.      如果只有n,则n必须大于0;如果同时有n和max,则n必须不小 
  71.      于0,且不大于max 
  72.     */  
  73.     CMySemaphore(int n);  
  74.     CMySemaphore(int n, int max);  
  75.       
  76.     /* 
  77.      销毁一个信号量 
  78.     */  
  79.     ~CMySemaphore();  
  80.   
  81.     /* 
  82.      对信号量计数值做加1动作,信号量变为有信号状态,使得 
  83.      另一个等待该信号量的线程可以被调度 
  84.     */  
  85.     void Set();  
  86.   
  87.     /* 
  88.      对信号量计数值做减1动作,信号量变为无信号状态。若 
  89.      计数值变得大于0时,信号量才会变为有信号状态。 
  90.     */  
  91.     void Wait();  
  92.   
  93.     /* 
  94.      在给定的时间间隔里等待信号量变为有信号状态,若成功, 
  95.      则将计数值减1,否则将发生超时。 
  96.     */  
  97.     void Wait(long lMilliseconds);  
  98.   
  99.     /* 
  100.      在给定的时间间隔里等待信号量变为有信号状态,若成功, 
  101.      则将计数值减1,返回true;否则返回false。 
  102.     */  
  103.     bool TryWait(long lMilliseconds);  
  104.   
  105. private:  
  106.     CMySemaphore();  
  107.     CMySemaphore(const CMySemaphore&);  
  108.     CMySemaphore& operator = (const CMySemaphore&);  
  109. };  
  110.   
  111. inline void CMySemaphore::Set()  
  112. {  
  113.     SetImpl();  
  114. }  
  115.   
  116.   
  117. inline void CMySemaphore::Wait()  
  118. {  
  119.     WaitImpl();  
  120. }  
  121.   
  122.   
  123. inline void CMySemaphore::Wait(long lMilliseconds)  
  124. {  
  125.     if (!WaitImpl(lMilliseconds))  
  126.         cout<<"time out"<<endl;  
  127. }  
  128.   
  129. inline bool CMySemaphore::TryWait(long lMilliseconds)  
  130. {  
  131.     return WaitImpl(lMilliseconds);  
  132. }  
  133.   
  134. #endif  

MySemaphore.cpp

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

    下边是测试代码

[cpp]  view plain  copy
  1. // pthread_semaphore.cpp : 定义控制台应用程序的入口点。  
  2. //  
  3.   
  4. #include "MySemaphore.h"  
  5.   
  6.   
  7. //创建一个信号量,其计数值当前值为0,最大值为3  
  8. CMySemaphore g_MySem(0, 3);  
  9.   
  10. //线程函数  
  11. void * StartThread(void *pParam)  
  12. {  
  13.     //休眠1秒,确保主线程函数main中  
  14.     //创建工作线程下一句g_MySem.Set();先执行  
  15.     sleep(1);  
  16.   
  17.     g_MySem.Wait(); //信号量计数值减1  
  18.   
  19.     cout<<"Do print StartThread"<<endl;  
  20.   
  21.     return (void *)0;  
  22. }  
  23.   
  24. int main(int argc, char* argv[])  
  25. {  
  26.     pthread_t thread;  
  27.     pthread_attr_t attr;  
  28.   
  29.     assert ( !g_MySem.TryWait(10) );  
  30.   
  31.     g_MySem.Set(); //信号量计数值加1  
  32.   
  33.     g_MySem.Wait(); //信号量计数值减1  
  34.   
  35.     try  
  36.     {  
  37.         g_MySem.Wait(100);  
  38.         cout<<"must timeout"<<endl; //此处发生超时  
  39.     }  
  40.     catch (...)  
  41.     {  
  42.         cout<<"wrong exception"<<endl;  
  43.     }  
  44.   
  45.     g_MySem.Set();  
  46.     g_MySem.Set();  
  47.     assert ( g_MySem.TryWait(0) );  
  48.     g_MySem.Wait();  
  49.     assert ( !g_MySem.TryWait(10) );  
  50.   
  51.     //创建工作线程  
  52.     pthread_attr_init(&attr);  
  53.     pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);  
  54.     if (pthread_create(&thread,&attr, StartThread,NULL) == -1)  
  55.     {  
  56.         cout<<"StartThread: create failed"<<endl;  
  57.     }  
  58.   
  59.     g_MySem.Set();  
  60.   
  61.     //等待线程结束  
  62.     void *result;  
  63.     pthread_join(thread,&result);  
  64.   
  65.     assert ( !g_MySem.TryWait(10) ); //若将断言中的 ! 去掉,则会发生断言错误  
  66.   
  67.     //关闭线程句柄,释放资源  
  68.     pthread_attr_destroy(&attr);  
  69.   
  70.     int iWait;  
  71.     cin>>iWait;  
  72.     return 0;  
  73. }  

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


    由此可见,信号量机制很关键的一点就是计数值 m_n。


原创作品,欢迎转载,麻烦带上链接:http://blog.csdn.net/chexlong/article/details/7098813 谢谢合作!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值