前文在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. 使用windows live writer写cnblog-1 安装wlr

    Writer:在本地编辑有声在色的博客内容,发布到你的网络博客!   离线安装文件下载地址:http://dx1.itopdog.cn/soft/wlsetup-all.rar 下了好几个离线版本的, ...

  2. java练习题——字符串

    一.动手动脑之String.equals()方法: 判断s1和s2的内容相同s1.equals(s2). 判断s1和s2的地址相同s1 == s2. 二.整理String类的Length().char ...

  3. SpringMVC---springMVC配置文件(springweb.xml)简介

    再web.xml中设置HTTP请求的中央调度处理器DispatcherServlet时,会指定SpringMVC配置文件,这里取名springweb.xml是因设置DispatcherServlet时 ...

  4. Windows环境下svn服务器的安装步骤

    做为一个程序开发人员,就算自己一个人写程序,也应该有一个SVN版本控制系统,以便对开发代码进行有效的管理. 下载SVN服务器 下载地址是:http://subversion.apache.org/pa ...

  5. Hadoop 原理总结

    Hadoop 原理总结   一.Hadoop技术原理 Hdfs主要模块:NameNode.DataNode Yarn主要模块:ResourceManager.NodeManager 常用命令: 1)用 ...

  6. javascript类式继承模式#2——借用构造函数

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  7. python3.x 安装命令

    在root下执行下面的命令即可: sudo apt-get install python3-dev build-essential libssl-dev libffi-dev libxml2 libx ...

  8. 第二阶段团队冲刺-four

    昨天: 绘制logo. 今天: 用servlet完成名单打印功能. 遇到的问题: servlet中的获得的路径不是想要的.

  9. C++寒假学习计划

    课程 中国大学mooc西北工业大学c++程序设计 理由 本课程有48节,章节分类清晰,由许多小知识块组成,条例清晰便于学习,由基础开始,由浅入深,适合我这种小白. 计划 从2.8号至2.28除去2.1 ...

  10. nyoj 题目44 子串和

    子串和 时间限制:5000 ms  |  内存限制:65535 KB 难度:3   描述 给定一整型数列{a1,a2...,an},找出连续非空子串{ax,ax+1,...,ay},使得该子序列的和最 ...