前文在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. 笔记-scrapy-scarpyd

    笔记-scrapy-scarpyd 1.      scrapy部署 会写爬虫之后就是部署.管理爬虫了,下面讲一下如何部署scrapy爬虫. 现在使用较多的管理工具是Scrapyd. scrapyd是 ...

  2. PHP.26-TP框架商城应用实例-后台3-商品修改、删除

    商品修改{修改页一般与添加页有百分之九十的相似度} create($_POST,Model::MODEL_UPDATE):系统内置的数据操作包括Model::MODEL_INSERT(或者1)和Mod ...

  3. 4,远程连接Linux

    为什么要远程连接Linux 在实际的工作场景中,虚拟机界面或者物理服务器本地的终端都是很少接触的,因为服务器装完系统之后,都要拉倒IDC机房托管,如果是购买的云主机,那更碰不到服务器本体了,只能通过远 ...

  4. P2440 木材加工(二分答案)

    P2440 木材加工 要保护环境 题目描述 题目描述: 木材厂有一些原木,现在想把这些木头切割成一些长度相同的小段木头(木头有可能有 剩余),需要得到的小段的数目是给定的.当然,我们希望得到的小段木头 ...

  5. ListView.getChildCount() 详解

    ListView.getCount() 返回的所包含的item总个数 ListView.getChildCount() (ViewGroup.getChildCount()) 返回的是现实层面上所包含 ...

  6. Java中的初始化详细解析

    今天所要详细讲解的是Java中的初始化,也就是new对象的过程中,其程序的行走流程. 先说没有静态成员变量和静态代码块的情况. public class NormalInit { public sta ...

  7. loadrunner 欺骗ip设置

    工具准备:loadrunner12,windows 10 ip欺骗=ip wizard 前提条件:本机IP地址为固定地址,不是自动获取的地址 方法: 1.管理员身份打开cmd 2.输入命令:confi ...

  8. Python全栈工程师 (类变量、方法、继承、覆盖)

    ParisGabriel                每天坚持手写  一天一篇  决定坚持几年 为了梦想为了信仰    开局一张图 Python人工智能从入门到精通 补充: 实例方法都是操作实例对象 ...

  9. Hadoop平台K-Means聚类算法分布式实现+MapReduce通俗讲解

        Hadoop平台K-Means聚类算法分布式实现+MapReduce通俗讲解 在Hadoop分布式环境下实现K-Means聚类算法的伪代码如下: 输入:参数0--存储样本数据的文本文件inpu ...

  10. HDU 3856 Palindrome ( Manacher + RMQ + 二分 ) WA!!!

    不知道错在哪了,求大神指教!!! 思路:用manacher求出每个以str[i]为中心轴的回文串的长度,RMQ预处理区间最大值,对于每个查询,二分最大回文串长,判定是否可行. #include < ...