找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 4025|回复: 0

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

[复制链接]
发表于 2011-12-24 14:35:48 | 显示全部楼层 |阅读模式
    使用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
  1. #ifndef Semaphore_Header
  2. #define Semaphore_Header
  3. #include <iostream>
  4. #include <pthread.h>
  5. #include <errno.h>
  6. #include <assert.h>
  7. using namespace std;
  8. //------------------------------------------------------------------------
  9. class CSemaphoreImpl
  10. {
  11. protected:
  12.         CSemaphoreImpl(int n, int max);               
  13.         ~CSemaphoreImpl();
  14.         void SetImpl();
  15.         void WaitImpl();
  16.         bool WaitImpl(long lMilliseconds);
  17. private:
  18.         volatile int    m_n;
  19.         int             m_max;
  20.         pthread_mutex_t m_mutex;
  21.         pthread_cond_t  m_cond;
  22. };
  23. inline void CSemaphoreImpl::SetImpl()
  24. {
  25.         if (pthread_mutex_lock(&m_mutex))       
  26.                 cout<<"cannot signal semaphore (lock)"<<endl;
  27.         if (m_n < m_max)
  28.         {
  29.                 ++m_n;
  30.         }
  31.         else
  32.         {
  33.                 pthread_mutex_unlock(&m_mutex);
  34.                 cout<<"cannot signal semaphore: count would exceed maximum"<<" m_n = "<<m_n<<"m_max = "<<m_max<<endl;
  35.         }
  36.         //重新开始等待m_cond的线程,可被调度
  37.         if (pthread_cond_signal(&m_cond))
  38.         {
  39.                 pthread_mutex_unlock(&m_mutex);
  40.                 cout<<"cannot signal semaphore"<<endl;
  41.         }
  42.         pthread_mutex_unlock(&m_mutex);
  43. }
  44. //------------------------------------------------------------------------
  45. /*
  46. 信号量同步机制
  47. 信号量提供一个计数值,可以进行原子操作。V 将计数值加1,使得
  48. 等待该信号量的线程可以被调用(调用Set()),P 将计数值减1,使
  49. 当前线程被挂起,进行睡眠(调用Wait())。
  50. 当信号量的计数值被初始化为0时,调用P操作,将挂起当前线程。
  51. 当信号量被激活,即调用V操作后,被挂起的线程就有机会被重新调度了。
  52. */
  53. class CMySemaphore: private CSemaphoreImpl
  54. {
  55. public:
  56.         /*
  57.          创建一个信号量,信号量计数值当前值为参数n,最大值为max。
  58.          如果只有n,则n必须大于0;如果同时有n和max,则n必须不小
  59.          于0,且不大于max
  60.         */
  61.         CMySemaphore(int n);
  62.         CMySemaphore(int n, int max);
  63.        
  64.         /*
  65.          销毁一个信号量
  66.         */
  67.         ~CMySemaphore();
  68.         /*
  69.          对信号量计数值做加1动作,信号量变为有信号状态,使得
  70.          另一个等待该信号量的线程可以被调度
  71.         */
  72.         void Set();
  73.         /*
  74.          对信号量计数值做减1动作,信号量变为无信号状态。若
  75.          计数值变得大于0时,信号量才会变为有信号状态。
  76.         */
  77.         void Wait();
  78.         /*
  79.          在给定的时间间隔里等待信号量变为有信号状态,若成功,
  80.          则将计数值减1,否则将发生超时。
  81.         */
  82.         void Wait(long lMilliseconds);
  83.         /*
  84.          在给定的时间间隔里等待信号量变为有信号状态,若成功,
  85.          则将计数值减1,返回true;否则返回false。
  86.         */
  87.         bool TryWait(long lMilliseconds);
  88. private:
  89.         CMySemaphore();
  90.         CMySemaphore(const CMySemaphore&);
  91.         CMySemaphore& operator = (const CMySemaphore&);
  92. };
  93. inline void CMySemaphore::Set()
  94. {
  95.         SetImpl();
  96. }
  97. inline void CMySemaphore::Wait()
  98. {
  99.         WaitImpl();
  100. }
  101. inline void CMySemaphore::Wait(long lMilliseconds)
  102. {
  103.         if (!WaitImpl(lMilliseconds))
  104.                 cout<<"time out"<<endl;
  105. }
  106. inline bool CMySemaphore::TryWait(long lMilliseconds)
  107. {
  108.         return WaitImpl(lMilliseconds);
  109. }
  110. #endif
  111. MySemaphore.cpp
  112. #include "MySemaphore.h"
  113. #include <sys/time.h>
  114. CSemaphoreImpl::CSemaphoreImpl(int n, int max): m_n(n), m_max(max)
  115. {
  116.         assert (n >= 0 && max > 0 && n <= max);
  117.         if (pthread_mutex_init(&m_mutex, NULL))
  118.                 cout<<"cannot create semaphore (mutex)"<<endl;
  119.         if (pthread_cond_init(&m_cond, NULL))
  120.                 cout<<"cannot create semaphore (condition)"<<endl;
  121. }
  122. CSemaphoreImpl::~CSemaphoreImpl()
  123. {
  124.         pthread_cond_destroy(&m_cond);
  125.         pthread_mutex_destroy(&m_mutex);
  126. }
  127. void CSemaphoreImpl::WaitImpl()
  128. {
  129.         if (pthread_mutex_lock(&m_mutex))
  130.                 cout<<"wait for semaphore failed (lock)"<<endl;
  131.         while (m_n < 1)
  132.         {
  133.                 //对互斥体进行原子的解锁工作,然后等待状态信号
  134.                 if (pthread_cond_wait(&m_cond, &m_mutex))
  135.                 {
  136.                         pthread_mutex_unlock(&m_mutex);
  137.                         cout<<"wait for semaphore failed"<<endl;
  138.                 }
  139.         }
  140.         --m_n;
  141.         pthread_mutex_unlock(&m_mutex);
  142. }
  143. bool CSemaphoreImpl::WaitImpl(long lMilliseconds)
  144. {
  145.         int rc = 0;
  146.         struct timespec abstime;
  147.         struct timeval tv;
  148.         gettimeofday(&tv, NULL);
  149.         abstime.tv_sec  = tv.tv_sec + lMilliseconds / 1000;
  150.         abstime.tv_nsec = tv.tv_usec*1000 + (lMilliseconds % 1000)*1000000;
  151.         if (abstime.tv_nsec >= 1000000000)
  152.         {
  153.                 abstime.tv_nsec -= 1000000000;
  154.                 abstime.tv_sec++;
  155.         }
  156.         if (pthread_mutex_lock(&m_mutex) != 0)
  157.                 cout<<"wait for semaphore failed (lock)"<<endl;
  158.         while (m_n < 1)
  159.         {
  160.                 //自动释放互斥体并且等待m_cond状态,并且限制了最大的等待时间
  161.                 if ((rc = pthread_cond_timedwait(&m_cond, &m_mutex, &abstime)))
  162.                 {
  163.                         if (rc == ETIMEDOUT) break;
  164.                         pthread_mutex_unlock(&m_mutex);
  165.                         cout<<"cannot wait for semaphore"<<endl;
  166.                 }
  167.         }
  168.         if (rc == 0) --m_n;
  169.         pthread_mutex_unlock(&m_mutex);
  170.         return rc == 0;
  171. }
  172. CMySemaphore::CMySemaphore(int n): CSemaphoreImpl(n, n)
  173. {
  174. }
  175. CMySemaphore::CMySemaphore(int n, int max): CSemaphoreImpl(n, max)
  176. {
  177. }
  178. CMySemaphore::~CMySemaphore()
  179. {
  180. }
复制代码
    下边是测试代码
  1. // pthread_semaphore.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "MySemaphore.h"
  4. //创建一个信号量,其计数值当前值为0,最大值为3
  5. CMySemaphore g_MySem(0, 3);
  6. //线程函数
  7. void * StartThread(void *pParam)
  8. {
  9.         //休眠1秒,确保主线程函数main中
  10.         //创建工作线程下一句g_MySem.Set();先执行
  11.         sleep(1);
  12.         g_MySem.Wait(); //信号量计数值减1
  13.         cout<<"Do print StartThread"<<endl;
  14.         return (void *)0;
  15. }
  16. int main(int argc, char* argv[])
  17. {
  18.         pthread_t thread;
  19.         pthread_attr_t attr;
  20.         assert ( !g_MySem.TryWait(10) );
  21.         g_MySem.Set(); //信号量计数值加1
  22.         g_MySem.Wait(); //信号量计数值减1
  23.         try
  24.         {
  25.                 g_MySem.Wait(100);
  26.                 cout<<"must timeout"<<endl; //此处发生超时
  27.         }
  28.         catch (...)
  29.         {
  30.                 cout<<"wrong exception"<<endl;
  31.         }
  32.         g_MySem.Set();
  33.         g_MySem.Set();
  34.         assert ( g_MySem.TryWait(0) );
  35.         g_MySem.Wait();
  36.         assert ( !g_MySem.TryWait(10) );
  37.         //创建工作线程
  38.         pthread_attr_init(&attr);
  39.         pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
  40.         if (pthread_create(&thread,&attr, StartThread,NULL) == -1)
  41.         {
  42.                 cout<<"StartThread: create failed"<<endl;
  43.         }
  44.         g_MySem.Set();
  45.         //等待线程结束
  46.         void *result;
  47.         pthread_join(thread,&result);
  48.         assert ( !g_MySem.TryWait(10) ); //若将断言中的 ! 去掉,则会发生断言错误
  49.         //关闭线程句柄,释放资源
  50.         pthread_attr_destroy(&attr);
  51.         int iWait;
  52.         cin>>iWait;
  53.         return 0;
  54. }
复制代码
    编译,运行。可以看到,与Win32平台上的测试结果相同



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




作者:chexlong 发表于2011-12-23 22:25:10 原文链接
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-5-4 06:47 , Processed in 0.015985 second(s), 7 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表