前文在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

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

MyEvent.cpp

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

下边是测试代码

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

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

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

Linux平台用C++实现事件对象,同步线程的更多相关文章

  1. Linux平台用C++实现事件对象,同步线程(转)

    本文属于转载,原文链接如下:http://blog.csdn.net/chexlong/article/details/7080537 与其相关的一组API包括:pthread_mutex_init, ...

  2. [C++] socket - 5 [API事件对象实现线程同步]

    /*API事件对象实现线程同步*/ #include<windows.h> #include<stdio.h> DWORD WINAPI myfun1(LPVOID lpPar ...

  3. 事件同步(一)-——CreateEvent( )事件对象实现线程同步

    事件对象分为两类:人工重置事件对象和自动重置事件对象.对于人工重置事件对象,可以同时有多个线程等待到事件对象,成为可调度线程. 对于自动重置事件对象,等待该事件对象的多个线程只能有一个线程成为可调度线 ...

  4. 转:VC++线程同步-事件对象

    这是整理孙鑫VC得到的关于线程同步方面的笔记. n       事件对象也属于内核对象,包含一个使用计数,一个用于指明该事件是一个自动重置的事件还是一个人工重置的事件的布尔值,另一个用于指明该事件处于 ...

  5. Windows多线程同步系列之三-----事件对象

    事件是一个内核事件,内核事件是什么呢,我理解也不深入也不好说,暂且理解为一个内核维护的数据类型吧通过内核事件同步主要 的方法是对事件的信号有和无来进行同步. 比如当我们一个线程进入一段临界代码(独占代 ...

  6. 第9章 用内核对象进行线程同步(1)_事件对象(Event)

    9.1 等待函数 (1)WaitForSingleObject(hObject,dwMilliseonds); ①dwMilliseconds为INFINITE时表示无限等待 ②dwMilliseco ...

  7. 转:sock_ev——linux平台socket事件框架(socket API的封装) .

    把linux平台提供的有关socket操作的API进行封装是有必要的:基于stream操作的流程与基于dgram操作的流程略有不同,分别放在两个类中,但两者又有很多相似的操作,因此写一个基类,让其继承 ...

  8. Linux 平台静默安装 Oracle客户端

    需求:Linux平台,安装完整版Oracle客户端 Tips:如果只是用到sqlldr,sqlplus功能,可以参考<Linux上oracle精简版客户端快速部署>快速部署精简版:如果需要 ...

  9. 【转】Redis安装整理(window平台和Linux平台)

    原文连接:http://zheng12tian.iteye.com/blog/1471726 原文作者:zheng12tian 转载注明以上信息! window平台Redis安装 redis wind ...

随机推荐

  1. Linux与BSD不同

    https://linux.cn/article-3186-1.html https://www.howtogeek.com/190773/htg-explains-whats-the-differe ...

  2. protobuf-2.5.0的下载与安装

    1.下载 Hadoop使用protocol buffer进行通信,需要下载和安装protobuf-2.5.0.tar.gz.由于现在protobuf-2.5.0.tar.gz已经无法在官网https: ...

  3. erlang节点局域网通信

    节点1: F:\WorkSpace\Server\src>erl -name hw@192.168.10.142 -setcookie 4213 consulting .erlang in &q ...

  4. 《Cracking the Coding Interview》——第11章:排序和搜索——题目1

    2014-03-21 20:35 题目:给定已升序排列的数组A和数组B,如果A有足够的额外空间容纳A和B,请讲B数组合入到A中. 解法:由后往前进行归并. 代码: // 11.1 Given two ...

  5. SQL多行变一列

    CREATE TABLE DEPT (DeptNo INT IDENTITY(1, 1)NOT NULL ,  Country VARCHAR(50) ,  Location VARCHAR(50) ...

  6. css 之 border-radius属性

    css中给盒子设置圆角可以通过 border-radius 属性来实现(具体原理就不深入探讨了); 在开发过程中都会遇到浏览器兼容问题,这问题其实也不难解决,无非就是加上私有前缀,在这里先忽略掉.   ...

  7. sqlalchemy 查询姿势总结

    sqlalchemy查询使用 1.带条件查询 查询是最常用的,对于各种查询我们必须要十分清楚,首先是带条件的查询 #带条件查询 rows = session.query(User).filter_by ...

  8. PAT——甲级1046S:shortest Distance

    这道题,折磨了我一个多小时,前前后后写了三个算法. 1046 Shortest Distance (20 point(s)) The task is really simple: given N ex ...

  9. 对象内存 (扩展 Data Structure Alignment)

    对于一个class object来说,我们需要多少内存才能表现出来,大致分为3类,这里在前面文章有内存图 (1)非静态数据成员的综合大小,这也符合了c++对象模型的结构 (2)填充字节,就是我们所说的 ...

  10. J2EE的十三个技术——EJB之消息驱动JMS

    JMS--Java Message Service JAVA的消息服务,消息可实现两端通信. 用于访问面向消息中间件的标准api,他提供与厂商无关的访问方法,以访问消息收发服务. 特点:即使其中一方不 ...