前文在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. 关于DIV内文字垂直居中的写法

    最近在写UI,或多或少用到了CSS,在这记录一下,今天用到的DIV内文字垂直居中的写法, 因为所做的项目都是基于WebKit内核浏览器演示的,所以我们今天采用的是-webkit-box的写法: dis ...

  2. Avril Lavigne : Everybody Hurts (Ver3)

    http://www.guitartabsexplorer.com/ http://www.guitartabsexplorer.com/lavigne-avril-Tabs/everybody-hu ...

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

    2014-03-21 21:37 题目:给定一个字符串数组,但是其中夹杂了很多空串“”,不如{“Hello”, “”, “World”, “”, “”, “”, “Zoo”, “”}请设计一个算法在其 ...

  4. flask利用session身份伪造

    想研究很久了,这次终于初步了解了flask session伪造(得知道密钥). python2和python3 session解密不一样,而且不都是base64,脚本https://github.co ...

  5. JavaScript显示当前时间的操作

    JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在HTML(标 ...

  6. [译]13-spring 内部bean

    spring基于xml配置元数据的方式下,位于property元素或者contructor-arg元素内的bean元素被称为内部bean,如下: <?xml version="1.0& ...

  7. 孤荷凌寒自学python第六十六天学习mongoDB的基本操作并进行简单封装5

    孤荷凌寒自学python第六十六天学习mongoDB的基本操作并进行简单封装5并学习权限设置 (完整学习过程屏幕记录视频地址在文末) 今天是学习mongoDB数据库的第十二天. 今天继续学习mongo ...

  8. Linux 查看当前日期和时间

    一.查看和修改Linux的时区 1. 查看当前时区 命令 : "date -R" 2. 修改设置Linux服务器时区 方法 A 命令 : "tzselect" ...

  9. 爬虫:Scrapy7 - Scrapy终端(Scrapy shell)

    Scrapy 终端是一个交互终端,可以在未启动 spider 的情况下尝试及调试你的爬取代码.其本意是用来测试提取数据的代码,不过可以将其作为正常的 Python 终端,在上面测试任何 Python ...

  10. 【bzoj4562】[Haoi2016]食物链 拓扑排序+dp

    原文地址:http://www.cnblogs.com/GXZlegend/p/6832118.html 题目描述 如图所示为某生态系统的食物网示意图,据图回答第1小题 现在给你n个物种和m条能量流动 ...