• c++代码如何实现在win/linux下跨线程间事务触发实现(含示例代码)


    目录

    一、c++跨线程间的“击鼓传花”-事务触发

    二、线程事务对象c++代码设计

    三、代码编译及测试

    四、补充


    一、c++跨线程间的“击鼓传花”-事务触发

            线程间事务机制本质上就是线程操作共享资源,最简单的实现,例如利用一个全局变量+全局互斥锁,各个线程就可以简单实现相互消息传递。
    在实际应用中,引入事件对象,本质就是将这些共享资源包装成一个事件对象,在调用的过程中,所有线程都可以在一个等待函数中指定事件对象句柄。当指定的事务对象的状态被置为有信号状态时,事务对象等待函数将返回,线程将获得通知而被触发。

            在win下,Windows API函数CreateEvent、WaitForSingleObject、SetEvent、ResetEvent、CloseHandle等实现事件对象的创建、设置、取值、重设、删除等操作,其内部使用了线程锁进行对象管理,实现跨线程事务相互调用。

            在 linux下,没有提供现成API函数调用,但基于类似实现原理,采用线程互斥锁对象(ptread_mutex_t),通过其相关的pthread_mutex_init、pthread_mutex_lock、pthread_mutex_unlock、pthread_cond_wait、pthread_mutex_destroy等配套函数,实现实现跨线程间事务相互调用。

    二、线程事务对象c++代码设计

            工程项目如下,测试层逻辑简单设计,创建一个event_handle,将其传递给线程对象,并进行事件等待命令,在主线程进行命令输入来触发事件信号,线程对象获得事件返回来执行后续操作。

    1. event_test
    2. bin
    3. build_win
    4. build_linux
    5. src
    6. event.h
    7. event.cpp
    8. myThread.h
    9. myThread.cpp
    10. win32Thread.h
    11. win32Thread.cpp
    12. testThread.h
    13. testThrad.cpp
    14. main.cpp
    15. CMakeLists.txt

    event.h:

    1. #ifndef _HIK_EVENT_H_
    2. #define _HIK_EVENT_H_
    3. #ifdef WIN32
    4. #include
    5. #define event_handle HANDLE
    6. #else
    7. #include
    8. typedef struct
    9. {
    10. bool state;
    11. bool manual_reset;
    12. pthread_mutex_t mutex;
    13. pthread_cond_t cond;
    14. }event_t;
    15. #define event_handle event_t*
    16. #endif
    17. //返回值:NULL 出错
    18. event_handle event_create(bool manual_reset, bool init_state);
    19. //返回值:0 等到事件,-1出错,句柄必须被触发信号后,函数才会返回
    20. int event_wait(event_handle hevent);
    21. //返回值:0 等到事件,1 超时,-1出错,建议比event_wait优先使用
    22. int event_timedwait(event_handle hevent, long milliseconds);
    23. //返回值:0 成功,-1出错
    24. int event_set(event_handle hevent);
    25. //返回值:0 成功,-1出错
    26. int event_reset(event_handle hevent);
    27. //返回值:无
    28. void event_destroy(event_handle hevent);
    29. #endif

    event.cpp

    1. #include "event.h"
    2. #ifdef __linux
    3. #include
    4. #include
    5. #endif
    6. #include
    7. event_handle event_create(bool manual_reset, bool init_state)
    8. {
    9. #ifdef WIN32
    10. HANDLE hevent = CreateEvent(NULL, manual_reset, init_state, NULL);
    11. #else
    12. event_handle hevent = new(std::nothrow) event_t;
    13. if (hevent == NULL)
    14. {
    15. return NULL;
    16. }
    17. hevent->state = init_state;
    18. hevent->manual_reset = manual_reset;
    19. if (pthread_mutex_init(&hevent->mutex, NULL))
    20. {
    21. delete hevent;
    22. return NULL;
    23. }
    24. if (pthread_cond_init(&hevent->cond, NULL))
    25. {
    26. pthread_mutex_destroy(&hevent->mutex);
    27. delete hevent;
    28. return NULL;
    29. }
    30. #endif
    31. return hevent;
    32. }
    33. int event_wait(event_handle hevent)
    34. {
    35. #ifdef WIN32
    36. DWORD ret = WaitForSingleObject(hevent, INFINITE);
    37. if (ret == WAIT_OBJECT_0)
    38. {
    39. return 0;
    40. }
    41. return -1;
    42. #else
    43. if (pthread_mutex_lock(&hevent->mutex))
    44. {
    45. return -1;
    46. }
    47. while (!hevent->state)
    48. {
    49. if (pthread_cond_wait(&hevent->cond, &hevent->mutex))
    50. {
    51. pthread_mutex_unlock(&hevent->mutex);
    52. return -1;
    53. }
    54. }
    55. if (!hevent->manual_reset)
    56. {
    57. hevent->state = false;
    58. }
    59. if (pthread_mutex_unlock(&hevent->mutex))
    60. {
    61. return -1;
    62. }
    63. return 0;
    64. #endif
    65. }
    66. int event_timedwait(event_handle hevent, long milliseconds)
    67. {
    68. #ifdef WIN32
    69. DWORD ret = WaitForSingleObject(hevent, milliseconds);
    70. if (ret == WAIT_OBJECT_0)
    71. {
    72. return 0;
    73. }
    74. if (ret == WAIT_TIMEOUT)
    75. {
    76. return 1;
    77. }
    78. return -1;
    79. #else
    80. int rc = 0;
    81. struct timespec abstime;
    82. struct timeval tv;
    83. gettimeofday(&tv, NULL);
    84. abstime.tv_sec = tv.tv_sec + milliseconds / 1000;
    85. abstime.tv_nsec = tv.tv_usec*1000 + (milliseconds % 1000)*1000000;
    86. if (abstime.tv_nsec >= 1000000000)
    87. {
    88. abstime.tv_nsec -= 1000000000;
    89. abstime.tv_sec++;
    90. }
    91. if (pthread_mutex_lock(&hevent->mutex) != 0)
    92. {
    93. return -1;
    94. }
    95. while (!hevent->state)
    96. {
    97. if ((rc = pthread_cond_timedwait(&hevent->cond, &hevent->mutex, &abstime)))
    98. {
    99. if (rc == ETIMEDOUT) break;
    100. pthread_mutex_unlock(&hevent->mutex);
    101. return -1;
    102. }
    103. }
    104. if (rc == 0 && !hevent->manual_reset)
    105. {
    106. hevent->state = false;
    107. }
    108. if (pthread_mutex_unlock(&hevent->mutex) != 0)
    109. {
    110. return -1;
    111. }
    112. if (rc == ETIMEDOUT)
    113. {
    114. //timeout return 1
    115. return 1;
    116. }
    117. //wait event success return 0
    118. return 0;
    119. #endif
    120. }
    121. int event_set(event_handle hevent)
    122. {
    123. #ifdef WIN32
    124. return !SetEvent(hevent);
    125. #else
    126. if (pthread_mutex_lock(&hevent->mutex) != 0)
    127. {
    128. return -1;
    129. }
    130. hevent->state = true;
    131. if (hevent->manual_reset)
    132. {
    133. if(pthread_cond_broadcast(&hevent->cond))
    134. {
    135. return -1;
    136. }
    137. }
    138. else
    139. {
    140. if(pthread_cond_signal(&hevent->cond))
    141. {
    142. return -1;
    143. }
    144. }
    145. if (pthread_mutex_unlock(&hevent->mutex) != 0)
    146. {
    147. return -1;
    148. }
    149. return 0;
    150. #endif
    151. }
    152. int event_reset(event_handle hevent)
    153. {
    154. #ifdef WIN32
    155. //ResetEvent 返回非零表示成功
    156. if (ResetEvent(hevent))
    157. {
    158. return 0;
    159. }
    160. return -1;
    161. #else
    162. if (pthread_mutex_lock(&hevent->mutex) != 0)
    163. {
    164. return -1;
    165. }
    166. hevent->state = false;
    167. if (pthread_mutex_unlock(&hevent->mutex) != 0)
    168. {
    169. return -1;
    170. }
    171. return 0;
    172. #endif
    173. }
    174. void event_destroy(event_handle hevent)
    175. {
    176. if(hevent){
    177. #ifdef WIN32
    178. CloseHandle(hevent);
    179. #else
    180. pthread_cond_destroy(&hevent->cond);
    181. pthread_mutex_destroy(&hevent->mutex);
    182. delete hevent;
    183. #endif
    184. }
    185. }

    win32Thread.h,win下父线程类实现

    1. #if _MSC_VER > 1000
    2. #pragma once
    3. #endif // _MSC_VER > 1000
    4. #ifndef WIN32THREAD_H
    5. #define WIN32THREAD_H
    6. #include
    7. #include
    8. typedef void *HANDLE;
    9. class MyThread
    10. {
    11. public:
    12. MyThread();
    13. ~MyThread();
    14. void start();
    15. virtual int Run();
    16. HANDLE getThread();
    17. private:
    18. HANDLE hThread;
    19. static void agent(void *p);
    20. };
    21. #endif

    win32Thread.cpp

    1. #include "win32Thread.h"
    2. #include
    3. MyThread::MyThread()
    4. {
    5. }
    6. MyThread::~MyThread()
    7. {
    8. WaitForSingleObject(hThread, INFINITE);
    9. }
    10. void MyThread::start()
    11. {
    12. hThread =(HANDLE)_beginthread(agent, 0, (void *)this);
    13. }
    14. int MyThread::Run()
    15. {
    16. printf("Base Thread\n");
    17. return 0;
    18. }
    19. void MyThread::agent(void *p)
    20. {
    21. MyThread *agt = (MyThread *)p;
    22. agt->Run();
    23. }
    24. HANDLE MyThread::getThread()
    25. {
    26. return hThread;
    27. }

    myThread.h,Linux下父线程类实现

    1. /*
    2. * add arg in linux system and compile: -lpthread
    3. */
    4. #ifndef _MYTHREAD_H
    5. #define _MYTHREAD_H
    6. #include
    7. #include
    8. class MyThread
    9. {
    10. private:
    11. //current thread ID
    12. pthread_t tid;
    13. //thread status
    14. int threadStatus;
    15. //get manner pointer of execution
    16. static void* run0(void* pVoid);
    17. //manner of execution inside
    18. void* run1();
    19. public:
    20. //threadStatus-new create
    21. static const int THREAD_STATUS_NEW = 0;
    22. //threadStatus-running
    23. static const int THREAD_STATUS_RUNNING = 1;
    24. //threadStatus-end
    25. static const int THREAD_STATUS_EXIT = -1;
    26. // constructed function
    27. MyThread();
    28. ~MyThread();
    29. //the entity for thread running
    30. virtual int Run()=0;
    31. //start thread
    32. bool start();
    33. //gte thread ID
    34. pthread_t getThreadID();
    35. //get thread status
    36. int getState();
    37. //wait for thread end
    38. void join();
    39. //wait for thread end in limit time
    40. void join(unsigned long millisTime);
    41. };
    42. #endif /* _MYTHREAD_H */

    myThread.cpp

    1. #include "myThread.h"
    2. #include
    3. void* MyThread::run0(void* pVoid)
    4. {
    5. MyThread* p = (MyThread*) pVoid;
    6. p->run1();
    7. return p;
    8. }
    9. void* MyThread::run1()
    10. {
    11. threadStatus = THREAD_STATUS_RUNNING;
    12. tid = pthread_self();
    13. Run();
    14. threadStatus = THREAD_STATUS_EXIT;
    15. tid = 0;
    16. pthread_exit(NULL);
    17. }
    18. MyThread::MyThread()
    19. {
    20. tid = 0;
    21. threadStatus = THREAD_STATUS_NEW;
    22. }
    23. MyThread::~MyThread()
    24. {
    25. join(10);
    26. }
    27. int MyThread::Run()
    28. {
    29. while(true){
    30. printf("thread is running!\n");
    31. sleep(100);
    32. }
    33. return 0;
    34. }
    35. bool MyThread::start()
    36. {
    37. return pthread_create(&tid, NULL, run0, this) == 0;
    38. }
    39. pthread_t MyThread::getThreadID()
    40. {
    41. return tid;
    42. }
    43. int MyThread::getState()
    44. {
    45. return threadStatus;
    46. }
    47. void MyThread::join()
    48. {
    49. if (tid > 0)
    50. {
    51. pthread_join(tid, NULL);
    52. }
    53. }
    54. void MyThread::join(unsigned long millisTime)
    55. {
    56. if (tid == 0)
    57. {
    58. return;
    59. }
    60. if (millisTime >0)
    61. {
    62. unsigned long k = 0;
    63. while (threadStatus != THREAD_STATUS_EXIT && k <= millisTime)
    64. {
    65. usleep(100);
    66. k++;
    67. }
    68. }
    69. join();
    70. }

    testThread.h,基于自定义win父线程类或linux父线程类为基类,实现等待事件响应输出

    1. #if _MSC_VER > 1000
    2. #pragma once
    3. #endif // _MSC_VER > 1000
    4. #ifndef TIME_UP_INFO_H
    5. #define TIME_UP_INFO_H
    6. /*
    7. 测试线程,测试事件类跨线程通信机制.
    8. */
    9. #ifdef WIN32
    10. #include "win32Thread.h"
    11. #endif
    12. #ifdef linux
    13. #include "myThread.h"
    14. #endif
    15. #include "event.h"
    16. class TestThread : public MyThread
    17. {
    18. public:
    19. TestThread(event_handle handle_);
    20. ~TestThread();
    21. int Run();
    22. private:
    23. bool running;
    24. event_handle handle_test;
    25. };
    26. #endif

    testThread.cpp

    1. #include "testThread.h"
    2. #include
    3. #ifdef WIN32
    4. #include
    5. #endif // WIN32
    6. #ifdef linux
    7. #include
    8. #endif
    9. TestThread::TestThread(event_handle handle_)
    10. : running(true)
    11. , handle_test(handle_)
    12. {
    13. };
    14. TestThread::~TestThread()
    15. {
    16. running = false;
    17. };
    18. int TestThread::Run()
    19. {
    20. int i=0,j=0;
    21. while (running)
    22. {
    23. //超时等待及持续等待测试
    24. if(0==event_timedwait(handle_test,10000))
    25. //if(0==event_wait(handle_test))
    26. {
    27. printf("event_wait success %d \n",++i);
    28. }else{
    29. printf("event_wait failed %d \n",++j);
    30. }
    31. #ifdef WIN32
    32. Sleep(10);
    33. #else
    34. usleep(10000);
    35. #endif
    36. }
    37. return 0;
    38. };

    main.cpp,创建一个事件对象,并传给测试线程类创建一个线程对象,在主线程捕获用户输入来触发事件设置,测试线程对象是否顺便获得事务通知,实现线程间消息传递。

    1. #ifdef WIN32
    2. #include
    3. #endif
    4. #ifdef linux
    5. #include
    6. #endif
    7. #include "event.h"
    8. #include "testThread.h"
    9. int main(int argc, char* argv[])
    10. {
    11. event_handle handle_ = event_create(false,true);
    12. //event_handle handle_ = event_create(true,true);
    13. if(NULL==handle_)
    14. {
    15. printf("event_create failed!\n");
    16. return 0;
    17. }
    18. TestThread th(handle_);
    19. th.start();
    20. bool bExit = false;
    21. char ch = '0';
    22. int i=1, j=0;
    23. while(!bExit)
    24. {
    25. ch = getchar();
    26. switch(ch)
    27. {
    28. case 'q':
    29. bExit = true;
    30. break;
    31. case 'w':
    32. if(0==event_set(handle_))
    33. printf("event_set success %d \n",++i);
    34. break;
    35. case 's':
    36. if(0==event_reset(handle_))
    37. printf("event_reset success %d \n",++j);
    38. break;
    39. default:
    40. break;
    41. }
    42. }
    43. event_destroy(handle_);
    44. printf("test exit!");
    45. return 0;
    46. }

    三、代码编译及测试

    win下采用cmake+vs2010,linux下采用cmake+gcc编译,CMakeLists.txt

    1. # CMake 最低版本号要求
    2. cmake_minimum_required (VERSION 2.8)
    3. # 项目信息
    4. project (event_test)
    5. #
    6. if(WIN32)
    7. message(STATUS "windows compiling...")
    8. add_definitions(-D_PLATFORM_IS_WINDOWS_)
    9. set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
    10. set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
    11. set(WIN_OS true)
    12. else(WIN32)
    13. message(STATUS "linux compiling...")
    14. add_definitions( -D_PLATFORM_IS_LINUX_)
    15. add_definitions("-Wno-invalid-source-encoding")
    16. # add_definitions("-O2")
    17. set(UNIX_OS true)
    18. set(_DEBUG true)
    19. endif(WIN32)
    20. #
    21. set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
    22. # 指定源文件的目录,并将名称保存到变量
    23. SET(source_h
    24. #
    25. ${PROJECT_SOURCE_DIR}/src/event.h
    26. ${PROJECT_SOURCE_DIR}/src/testThread.h
    27. )
    28. SET(source_cpp
    29. #
    30. ${PROJECT_SOURCE_DIR}/src/event.cpp
    31. ${PROJECT_SOURCE_DIR}/src/testThread.cpp
    32. ${PROJECT_SOURCE_DIR}/src/main.cpp
    33. )
    34. #头文件目录
    35. #include_directories(${PROJECT_SOURCE_DIR}/include)
    36. if (${UNIX_OS})
    37. SET(source_h_linux
    38. ${PROJECT_SOURCE_DIR}/src/myThread.h
    39. )
    40. SET(source_cpp_linux
    41. ${PROJECT_SOURCE_DIR}/src/myThread.cpp
    42. )
    43. add_definitions(
    44. "-W"
    45. "-fPIC"
    46. "-Wall"
    47. # "-Wall -g"
    48. "-Werror"
    49. "-Wshadow"
    50. "-Wformat"
    51. "-Wpointer-arith"
    52. "-D_REENTRANT"
    53. "-D_USE_FAST_MACRO"
    54. "-Wno-long-long"
    55. "-Wuninitialized"
    56. "-D_POSIX_PTHREAD_SEMANTICS"
    57. "-DACL_PREPARE_COMPILE"
    58. "-Wno-unused-parameter"
    59. "-fexceptions"
    60. )
    61. set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0")
    62. link_directories()
    63. # 指定生成目标
    64. add_executable(event_test ${source_h} ${source_cpp} ${source_h_linux} ${source_cpp_linux})
    65. #link
    66. target_link_libraries(event_test
    67. -lpthread -pthread -lz -lrt -ldl
    68. )
    69. endif(${UNIX_OS})
    70. if (${WIN_OS})
    71. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4819")
    72. SET(source_h_win
    73. ${PROJECT_SOURCE_DIR}/src/win32Thread.h
    74. )
    75. SET(source_cpp_win
    76. ${PROJECT_SOURCE_DIR}/src/win32Thread.cpp
    77. )
    78. add_definitions(
    79. "-D_CRT_SECURE_NO_WARNINGS"
    80. "-D_WINSOCK_DEPRECATED_NO_WARNINGS"
    81. "-DNO_WARN_MBCS_MFC_DEPRECATION"
    82. "-DWIN32_LEAN_AND_MEAN"
    83. )
    84. link_directories()
    85. if (CMAKE_BUILD_TYPE STREQUAL "Debug")
    86. set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/bin)
    87. # 指定生成目标
    88. add_executable(event_testd ${source_h} ${source_cpp} ${source_h_win} ${source_cpp_win})
    89. else(CMAKE_BUILD_TYPE)
    90. set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/bin)
    91. # 指定生成目标
    92. add_executable(event_test ${source_h} ${source_cpp} ${source_cpp_win})
    93. endif (CMAKE_BUILD_TYPE)
    94. endif(${WIN_OS})

    编译命令如下

    1. 进入event_test目录
    2. win:
    3. mkdir build_win
    4. cmake -G "Visual Studio 10 2010 Win64" -DCMAKE_BUILD_TYPE=Release ..
    5. msbuild event_test.sln /p:Configuration="Release" /p:Platform="x64"
    6. Linux:
    7. mkdir build_linux
    8. cmake ..
    9. make

    省略编译过程,以下是输出程序运行效果,左边是linux程序:

    四、补充

    完整的示例代码已经上传CSDN:

    c++代码如何实现在win/linux下跨线程间事务触发实现完整示例代码-C++文档类资源-CSDN下载

  • 相关阅读:
    English语法_不定代词 - 常用短语
    解线性方程组——(Gauss-Seidel)高斯-赛德尔迭代法 | 北太天元
    js之继承
    以太网基础学习(三)——UDP协议
    LeetCode_位运算_中等_318.最大单词长度乘积
    08、Metasploit渗透测试之信息收集
    【C刷题初阶】刷爆力扣第一弹
    Unity TrailRenderer实现拖尾
    语法基础(变量、输入输出、表达式与顺序语句)
    【LinuxShell】linux防火墙之SNAT策略和DNAT策略
  • 原文地址:https://blog.csdn.net/py8105/article/details/126836223