C++多线程实例之互斥量同步

本文介绍了一种跨平台的互斥量封装方法,支持Windows和Linux系统,并提供了多线程生产者-消费者模式下的应用实例。通过封装互斥量和条件变量为CMutexLock类,简化了多线程同步的复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

要点:将互斥量 + 条件变量/事件对象封装为了一个类CMutexLock,该类同时支持windows和linux下的互斥量同步。对熟悉windows和linux下面的多线程开发很有帮助。下面的代码可以直接在VS2008,2010中编译通过,linux下也是没问题的。如果你觉得写得不错也可以直接移植到你的代码库中,比较适合多线程中采用生产者-消费者这样的场景,比如子线程读取和解析文件生产给其它线程用,网络接收子线程接收处理数据给其它线程使用等。

强烈建议有需要的跑起来调试下(本项目类型是VS win32项目cpp中需要#include "stdafx.h",其它类型项目或者linux下简单修改下即可),代码注释中有详细的说明。如果你觉得有更好的做法,或者那里注释错了,非常欢迎你的回复。本代码也是参考了很多网上的资料,感谢参考文章中的各位作者。

工程设置:

1.pthread多线程库使用:

pthread库源代码:ftp://sources.redhat.com/pub/pthreads-win32/
本项目下载的是:pthreads-w32-2-9-1-release.zip 解压Pre-built.2就是要包含的库,pthreadVC2.dll拷贝到C:\Windows\System32下。

VC工程设置:
头文件:../../pthreads-w32-2-9-1-release\Pre-built.2\include
库目录:../../pthreads-w32-2-9-1-release\Pre-built.2\lib\x86
库:pthreadVC2.lib
代码包含头文件:#include <pthread.h>

2.windows下
VC工程设置ProjectàSetting-->C/C++-->Code generation->run-time library 选择Multi-threaded 或者Multithreaded。
即使用: MT或MD。
代码包含头文件:
#include <Windows.h>
#include <process.h> 

多线程代码:

例子,具体用法和分析见代码注释:

MutexLock.h

[cpp]  view plain  copy
  1. #ifndef _MUTEXLOCK_H_  
  2. #define _MUTEXLOCK_H_  
  3.   
  4. #ifdef WIN32  
  5. //#define WINOS // 这里可以注释掉就是linux形式的互斥量  
  6. #else  
  7. #undef  WINOS  
  8. #endif  
  9.   
  10. #ifdef WINOS  
  11. #include <Windows.h>  
  12. #include <process.h>   
  13. #else  
  14. #include <pthread.h>  
  15. //来自ftp://sources.redhat.com/pub/pthreads-win32/  
  16. /* 获取互斥量属性对象在进程间共享与否的标志  
  17. int pthread_mutexattr_getpshared (__const pthread_mutexattr_t *__restrict __attr, \   
  18.                                   int *__restrict __pshared);   
  19.  设置互斥量属性对象,标识在进程间共享与否 
  20. int pthread_mutexattr_setpshared (pthread_mutexattr_t *__attr, int __pshared);  
  21. 底层库都像一个状态机,包括socket,pthread,directx,opengl,openal... 
  22. 这是对外统一接口,松耦合,但是又可能需要调整内部的参数,那么必须采用这样的方式,不论编写的语言是基于过程还是基于对象的。 
  23.  */  
  24. /*参考文章:http://www.ibm.com/developerworks/cn/linux/l-cn-mthreadps/ 
  25. http://blog.youkuaiyun.com/anonymalias/article/details/9093733 
  26. https://software.intel.com/zh-cn/blogs/2011/03/24/linux-windows 
  27. */  
  28. #endif  
  29.   
  30. class CMutexLock  
  31. {  
  32. public:  
  33.     CMutexLock();  
  34.     ~CMutexLock();  
  35.     void init();  
  36.     void release();  
  37.     void lock();  
  38.     void unlock();// 设计的时候,不要unwaite放置到unlock里面去,否则会导致职责不分明,如果有内部控制的还会导致无法唤醒。  
  39.     void waite();// 当获取不到数据,那么waite挂起线程,等待其它线程通知释放  
  40.     void unwaite();// 生产了数据那么需要调用unwaite.  
  41. private:  
  42.     #ifdef WINOS  
  43.         HANDLE m_mutex;  
  44.         HANDLE m_event;//事件如果有信号那么可以正常执行,如果无信号那么只能等待  
  45.     #else  
  46.         pthread_mutex_t m_mutex;  
  47.         pthread_cond_t m_condition;  
  48.         pthread_mutexattr_t m_mutexAttr;  
  49.     #endif  
  50. };  
  51.   
  52. #endif  

MutexLock.cpp

[cpp]  view plain  copy
  1. #include "stdafx.h"  
  2. #include "MutexLock.h"  
  3. /*参考文章: 
  4. https://msdn.microsoft.com/en-us/library/windows/desktop/ms682411%28v=vs.85%29.aspx 
  5. http://blog.youkuaiyun.com/anonymalias/article/details/9080881 
  6. http://blog.youkuaiyun.com/anonymalias/article/details/9174403 
  7. */  
  8. CMutexLock::CMutexLock()  
  9. {  
  10.       
  11. #ifndef WINOS  
  12.     m_mutex = NULL;  
  13.     m_condition = NULL;  
  14. #else  
  15.     m_mutex = NULL;  
  16.     m_event = NULL;  
  17. #endif  
  18. }  
  19. CMutexLock::~CMutexLock()  
  20. {  
  21.     release();  
  22. }  
  23. void CMutexLock::release()  
  24. {  
  25. #ifdef WINOS  
  26.     CloseHandle(m_mutex);//所有内核对象,或者用其它方式创建的,都可以用closeHandle将引用计数减1。  
  27.     m_mutex = NULL;  
  28. #else  
  29.     pthread_mutexattr_destroy(&m_mutexAttr);  
  30.     pthread_mutex_destroy(&m_mutex);  
  31.     pthread_cond_destroy(&m_condition);  
  32.     m_mutex = NULL;  
  33.     m_condition = NULL;  
  34. #endif  
  35. }  
  36.   
  37. void CMutexLock::init()  
  38. {  
  39. #ifdef WINOS  
  40.     // arg1 是NULL,互斥量用默认的安全描述信息,这个时候子进程不能继承该互斥量.  
  41.     // arg2 是当前指明互斥量指向的线程为空,且被引用的次数是0,没有线程/进程拥有该互斥量;否则当前线程拥有该互斥量。  
  42.     // arg3 互斥量的名字  
  43.     m_mutex = CreateMutex(NULL, FALSE, NULL);  
  44.     DWORD dwLastError = GetLastError();  
  45.     if( dwLastError == ERROR_ALREADY_EXISTS)  
  46.     {  
  47.         CloseHandle(m_mutex);  
  48.         m_mutex = NULL;  
  49.     }  
  50.     //事件是有信号线程不阻塞,无信号阻塞线程睡眠。  
  51.     // arg1是事件属性。  
  52.     // arg2是手动还是自动调用ResetEvent将事件设置为无信号,SetEvent是将事件设置为有信号  
  53.     // ResetEvent是否手动设置为无信号,WaitForSingleObject后如果是自动方式那么会自动调用ResetEvent将事件设置为无信号。  
  54.     // arg3是初始状态信号,一般设置为FALSE无信号,让线程挂起阻塞。  
  55.     // arg4是线程的名字。  
  56.     m_event = CreateEvent(NULL, FALSE, FALSE, NULL);  
  57. #else  
  58.     // arg1是初始化的互斥量,arg2是pthread_mutexattr_t属性指针,如果是NULL,那么没有线程拥有该初始化好的互斥量。  
  59.     int nResult = pthread_mutex_init(&m_mutex, NULL);  
  60.     if(nResult == 0)  
  61.      {  
  62.          printf("pthread_mutex_init result OK.\n");  
  63.      }  
  64.      else  
  65.      {  
  66.          printf("pthread_mutex_init result error:%d\n", nResult);  
  67.      }  
  68.     pthread_mutexattr_init(&m_mutexAttr);   
  69.     // 设置 recursive 属性,使得linux下可以递归加锁,避免递归加锁死锁。  
  70.     pthread_mutexattr_settype(&m_mutexAttr,PTHREAD_MUTEX_RECURSIVE_NP);   
  71.     pthread_mutex_init(&m_mutex, &m_mutexAttr);  
  72.   
  73.     pthread_cond_init(&m_condition, NULL);  
  74. #endif  
  75. }  
  76.   
  77. void CMutexLock::lock()  
  78. {  
  79. #ifdef WINOS  
  80.     // arg2是等待毫秒时间,INFINITE是永远等待,直到该内核对象被触发可用;该函数是一个异步调用函数,互斥量拥有线程id非0,  
  81.     // 那么该函数将被挂起阻塞,释放当前CPU拥有权,当被其它线程释放互斥量拥有线程id为0,将会唤醒当前阻塞的线程重新获取互斥量。  
  82.     WaitForSingleObject(m_mutex, INFINITE);  
  83.     /*if(WaiteforSingleObject(m_hMutex, dwMilliSec) == WAIT_OBJECT_0) 
  84.     { 
  85.         return true; 
  86.     } 
  87.     return false; 
  88.     */  
  89. #else  
  90.     // 锁定互斥锁,如果该互斥锁被其它线程拥有,那么将被挂起阻塞,指定可用才回调返回;  
  91.     // 线程自己多次锁定将会导致死锁;两个线程需要多个互斥锁相互等待对方的互斥锁,也会导致死锁。  
  92.     pthread_mutex_lock(&m_mutex);   
  93. #endif  
  94. }  
  95.   
  96. void  CMutexLock::waite()  
  97. {  
  98. #ifdef WINOS  
  99.     WaitForSingleObject(m_event, INFINITE);// 等待的事件,和时间  
  100. #else  
  101.     //会自动调用pthread_mutex_unlock(&m_mutex)释放互斥量,将当前线程挂起阻塞,等待对方线程pthread_cond_signal通知唤醒,  
  102.     // 唤醒后pthread_cond_wait会调用pthread_mutex_lock重新锁定互斥量。  
  103.     // pthread_cond_timedwait是阻塞一段时间。  
  104.     pthread_cond_wait(&m_condition, &m_mutex);  
  105. #endif  
  106. }  
  107.   
  108. void CMutexLock::unwaite()  
  109. {  
  110. #ifdef WINOS  
  111.     SetEvent(m_event);//设置为有信号,唤醒等待事件挂起的线程。  
  112. #else  
  113.     pthread_cond_signal(&m_condition);//pthread_cond_broadcast(pthread_cond_t * cond)唤醒在条件上等待的所有线程。  
  114. #endif  
  115.   
  116. }  
  117.   
  118. void CMutexLock::unlock()  
  119. {  
  120. #ifdef WINOS  
  121.     ReleaseMutex(m_mutex);// 将互斥量释放,会通知到WaitForSingleObject.  
  122. #else  
  123.     pthread_mutex_unlock(&m_mutex);  
  124. #endif  
  125. }  
main.cpp
[cpp]  view plain  copy
  1. /*多线程的一些总结: 
  2. 一、互斥量是拥有线程ID的,如果互斥量没有线程ID那么当前线程可以获得互斥量,互斥量函数非阻塞;否则互斥量函数将阻塞当前线程。 
  3.     linux下条件变量初始化时是没有绑定互斥量的(无信号的),只要waite都会释放当前互斥量,阻塞当前线程,直到有signal发送过来才会唤醒。 
  4.     window下的事件对象,事件对象无信号情况下会阻塞当前线程,通过SetEvent(m_event)可以触发事件(signal),让当前阻塞的线程唤醒。 
  5. 二、采用等待机制等有效的提高程序的CPU利用率,注意等待时需要先释放所用拥有的锁(尽管之前释放过,),否则会导致死锁。 
  6. s_mutexFileContent.unlock();// 不加这句linux的pthread库会导致死锁,linux不能递归加锁否则会导致死锁,windows下却可以。 
  7. s_mutexRequent.unlock(); // 不加这句,windows下的WaitForSingleObject不会先释放互斥量锁,也会导致死锁。 
  8.  
  9. //s_mutexRequent.waite(); 
  10. 三、pthread.h库下默认创建的线程是可结合的,每个可结合线程都应该要么被显示地回收,即调用pthread_join; 
  11. 要么通过调用pthread_detach函数分离子线程,子线程被分离后不能再结合了。 
  12. pthread_detach(s_loadingThread); 
  13.  
  14. 四、window下的WaitForSingleObject线程未运行时候是未触发的,当线程运行完那么是触发的,所以可以等到到线程。 
  15. //返回WAIT_OBJECT_0在指定时间内等到到,WAIT_TIMEOUT超时,WAIT_FAILED有错误。 
  16. HANDLE handle = CreateThread(NULL, 0, ThreadFun, NULL, 0, NULL);   
  17. WaitForSingleObject(handle, INFINITE); 
  18. 五、windows下众多多线程函数的选择;_beginthread是_beginthreadex的子集参数受限制,释放会有差异,所以用_beginthreadex即可。 
  19. _beginthreadex内部会调用CreateThread(),会给C运行库函数开辟堆资源,所以要用_endthreadex和CloseHandle来避免内存泄露。 
  20. CreateThread()没有开辟堆资源,所以在C运行库中可能导致多线程数据异常风险,但是在Win32/MFC C++运行库中可以放心使用。 
  21. AfxBeginThread()是MFC中的多线程,分工作线程无消息循环,界面线程有消息循环,可以让当前线程创建,挂起,唤醒,终止。 
  22. windows下线程常用函数:DWORD SuspendThread(HANDLE hThread);DWORD ResumeThread(HANDLE hThread);BOOL SetThreadPriority(HANDLE hThread,int nPriority); 
  23. VOID ExitThread(DWORD dwExitCode); BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);  
  24. 一般线程的挂起/唤醒都通过同步对象来实现。 
  25.  
  26. 如果在代码中有使用标准C运行库中的函数时,尽量使用_beginthreadex()来代替CreateThread()。 
  27. window下的多线程底层都是对CreateThread的封装。 
  28. 如果在除主线程之外的任何线程中进行一下操作,你就应该使用多线程版本的C runtime library,并使用_beginthreadex和_endthreadex,CloseHandle: 
  29. 1 使用malloc()和free(),或是new和delete 
  30. 2 使用stdio.h或io.h里面声明的任何函数 
  31. 3 使用浮点变量或浮点运算函数 
  32. 4 调用任何一个使用了静态缓冲区的runtime函数,比如:asctime(),strtok()或rand() 
  33.  
  34. 六、linux和window下互斥量和条件变量的区别 
  35. 1.linux连续上锁会死锁,可以用 pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE_NP); 解决。windows连续上锁不会死锁。 
  36. 2.SetEvent(m_event)后等待事件对象一直是有signal的,后面waite的不会阻塞;linux下pthread_cond_signal不会一直有信号,后面waite的将会阻塞。 
  37. 3.pthread_cond_wait()后不需要重新加锁,WaitForSingleObject/SignalObjectAndWait后需要重新加锁。 
  38. 4.linux的pthread_cond_timedwait等待的是绝对时间1970-01-01 00:00:00 开始的时间,window的WaitForSingleObject是一个从当前开始的相对时间。  
  39. 5.linux的线程释放,非游离的线程需要主线程调用pthread_join等待子线程结束并释放子线程的栈寄存器,游离的线程需要设置为属性为游离, 
  40. 或者创建后用pthread_detach设置,子线程结束时候系统会回收子线程的资源。这样才能避免内存泄露。 
  41. windows下的释放:_beginthreadex创建的要调用_endthreadex和CloseHandle,其它方式创建的线程ExitThread或CloseHanle即可。 
  42. */  
  43. #include "stdafx.h"  
  44. #include "MutexLock.h"  
  45. #include <iostream>  
  46. #include <deque>  
  47. #include <string>  
  48. using namespace std;  
  49. #include <windows.h>  
  50.   
  51. // 异步线程  
  52. #ifdef WINOS  
  53. static HANDLE s_loadingThread = NULL;  
  54. #else  
  55. static pthread_t s_loadingThread;  
  56. #endif  
  57. // 异步读取文件的互斥量  
  58. static CMutexLock s_mutexRequent;  
  59. // 异步渲染的互斥量  
  60. static CMutexLock s_mutexFileContent;  
  61.   
  62. // 根对象,派生Node  
  63. class Object  
  64. {  
  65. public:  
  66.     Object()  
  67.     {  
  68.         m_dObjID = 0;  
  69.     }  
  70. protected:  
  71.     double m_dObjID;  
  72. };  
  73. // 异步加载后的回调函数  
  74. typedef  void (* ObjectCallBack)(Object* );  
  75.   
  76. typedef struct tagAsyncFileData  
  77. {  
  78.     bool m_bLoadOK;  
  79.     Object *m_pTarget;  
  80.     ObjectCallBack m_pCallback;  
  81.     string strFilePath;  
  82.     tagAsyncFileData()  
  83.     {  
  84.         m_bLoadOK = false;  
  85.         m_pTarget = NULL;  
  86.         m_pCallback = NULL;  
  87.         strFilePath.clear();  
  88.     }  
  89. }AsyncFileData;  
  90.   
  91. static deque<AsyncFileData*> s_dataFileRequent;  
  92.   
  93. typedef struct tagFileBufferData  
  94. {  
  95.     AsyncFileData *m_pAsyncFileData;  
  96.     char *m_pBuffer;  
  97.     tagFileBufferData()  
  98.     {  
  99.         m_pAsyncFileData = NULL;  
  100.         m_pBuffer = NULL;  
  101.     }  
  102. }AsyncFileBufferData;  
  103.   
  104. static deque<AsyncFileBufferData*> s_dataFileContent;  
  105.   
  106. #ifdef WINOS  
  107. unsigned __stdcall AsyncLoad(void *pParameter)    
  108. #else  
  109. static void* AsyncLoad(void *pParameter)  
  110. #endif  
  111. {  
  112.     while(1)  
  113.     {  
  114.         AsyncFileData *pFileData = NULL;  
  115.         s_mutexRequent.lock();  
  116.         if(s_dataFileRequent.empty())  
  117.         {  
  118.             // 如果没有数据过来那么释放当前的锁,挂起CPU等待  
  119.             printf("子线程,因没有请求的文件而等待!\n");  
  120.             s_mutexFileContent.unlock();// 不加这句linux的pthread库会导致死锁。  
  121.             s_mutexRequent.unlock(); // 不加这句,windows下的WaitForSingleObject不会先释放互斥量锁,也会导致死锁。  
  122.             s_mutexRequent.waite();  
  123.               
  124.             continue;  
  125.         }  
  126.         else  
  127.         {  
  128.             pFileData = s_dataFileRequent.front();  
  129.             s_dataFileRequent.pop_front();  
  130.         }  
  131.         s_mutexRequent.unlock();  
  132.           
  133.   
  134.         // 得到数据处理  
  135.         if(pFileData != NULL)  
  136.         {  
  137.             // 异步加载数据,此次mmap还是fread方式略去,直接设置加载OK  
  138.             //fopen(pFileData->strFilePath.c_str(), "rb");  
  139.             Sleep(1000);  
  140.             pFileData->m_bLoadOK = true;  
  141.             //pFileData.m_pTarget  
  142.             AsyncFileBufferData *pAsyncBuffer  = new AsyncFileBufferData;  
  143.             pAsyncBuffer->m_pAsyncFileData = pFileData;  
  144.             char *pContent = "data from pFileData's strFilePath...";  
  145.             int nContenLen = strlen(pContent) + 1;  
  146.             pAsyncBuffer->m_pBuffer = new char[nContenLen];  
  147.             strcpy_s(pAsyncBuffer->m_pBuffer, nContenLen, pContent);  
  148.             printf("子线程 读取文件: %s\n", pAsyncBuffer->m_pAsyncFileData->strFilePath.c_str());  
  149.               
  150.             // 异步处理锁  
  151.             s_mutexFileContent.lock();  
  152.             // 解析好的数据放置进来  
  153.             s_dataFileContent.push_back(pAsyncBuffer);  
  154.             s_mutexFileContent.unlock();  
  155.             s_mutexFileContent.unwaite();  
  156.         }  
  157.     }  
  158. #ifdef WINOS  
  159.     _endthreadex( 0 );// 释放_beginthreadex分配的堆资源,且还要用CloseHandle释放  
  160.     return 0;  
  161. #endif  
  162. }  
  163.   
  164. int main(int argc, char* argv[])    
  165. {   
  166.     s_mutexRequent.init();  
  167.     s_mutexFileContent.init();  
  168. #ifdef WINOS  
  169.     unsigned int uiThreadID;  
  170.     s_loadingThread = (HANDLE)_beginthreadex(NULL, 0, AsyncLoad, NULL, CREATE_SUSPENDED, &uiThreadID);   
  171.     /*_CRTIMP uintptr_t __cdecl _beginthreadex(_In_opt_ void * _Security, _In_ unsigned _StackSize, 
  172.         _In_ unsigned (__stdcall * _StartAddress) (void *), _In_opt_ void * _ArgList,  
  173.         _In_ unsigned _InitFlag, _In_opt_ unsigned * _ThrdAddr);*/  
  174.     if(s_loadingThread == NULL)  
  175.     {  
  176.         printf("pthread_create error!");  
  177.         return 0;  
  178.     }  
  179.     ResumeThread(s_loadingThread);   
  180. #else  
  181.     if( pthread_create(&s_loadingThread, NULL, AsyncLoad, NULL) != 0)  
  182.     {  
  183.         printf("pthread_create error!");  
  184.         return 0;  
  185.     }  
  186.     pthread_detach(s_loadingThread);  
  187. #endif  
  188.     // 在任何一个时间点上,线程是可结合的(joinable)或者是分离的(detached)。一个可结合的线程能够被其他线程收回其资源和杀死。  
  189.     // 在被其他线程回收之前,它的存储器资源(例如栈)是不释放的。相反,一个分离的线程是不能被其他线程回收或杀死的,  
  190.     // 它的存储器资源在它终止时由系统自动释放。默认情况下,线程被创建成可结合的。为了避免存储器泄漏,  
  191.     // 每个可结合线程都应该要么被显示地回收,即调用pthread_join;要么通过调用pthread_detach函数被分离。  
  192.   
  193.     // pthread_detach(s_loadingThread);分离,运行结束后子线程会自动释放自己资源,不需要pthread_join也可以完全释放资源。  
  194.     //   void* ret = NULL;  
  195.     // pthread_join(_subThreadInstance, &ret);主线程一直等待直到等待的线程结束自己才结束,主线程可以清理其它线程的栈寄存器。  
  196.     // pthread_self()获取自身线程的id.  
  197.     // 线程的被动结束分为两种,一种是异步终结,另外一种是同步终结。异步终结就是当其他线程调用 pthread_cancel的时候,  
  198.     // 线程就立刻被结束。而同步终结则不会立刻终结,它会继续运行,直到到达下一个结束点(cancellation point)。  
  199.     // 当一个线程被按照默认的创建方式创建,那么它的属性是同步终结。  
  200.     static int fileCount = 0;  
  201.     while(1)  
  202.     {  
  203.         s_mutexRequent.lock();  
  204.         AsyncFileData* m_pFileData = new AsyncFileData();  
  205.         m_pFileData->m_bLoadOK = false;  
  206.         m_pFileData->m_pCallback = NULL;  
  207.         m_pFileData->m_pTarget = NULL;  
  208.         fileCount++;  
  209.         char szFileBuffer[256];  
  210.         sprintf_s(szFileBuffer,"文件名 %d.", fileCount);  
  211.         m_pFileData->strFilePath = szFileBuffer;  
  212.         printf("主线程,请求读取文件: %s\n", m_pFileData->strFilePath.c_str());  
  213.         s_dataFileRequent.push_back(m_pFileData);  
  214.         s_mutexRequent.unlock();  
  215.         s_mutexRequent.unwaite();  
  216.   
  217.         // 其它逻辑  
  218.         Sleep(1000);  
  219.   
  220.         while(1)  
  221.         {  
  222.             AsyncFileBufferData *pAsyncBuffer = NULL;  
  223.   
  224.             s_mutexFileContent.lock();  
  225.             if(s_dataFileContent.empty())  
  226.             {  
  227.                 printf("主线程,因没有解析好的数据等待!\n");  
  228.                 s_mutexRequent.unlock();// 请求锁需要释放,否则会导致问题  
  229.                 s_mutexFileContent.unlock();  
  230.                 s_mutexFileContent.waite();// 读取线程还没解析好等待  
  231.                 continue;  
  232.             }  
  233.   
  234.             pAsyncBuffer = s_dataFileContent.front();  
  235.             s_dataFileContent.pop_front();  
  236.             s_mutexFileContent.unlock();  
  237.   
  238.             if(pAsyncBuffer != NULL)  
  239.             {  
  240.                 printf("主线程,得到读取线程解析后的文件:%s, 数据: %s\n", pAsyncBuffer->m_pAsyncFileData->strFilePath.c_str(), pAsyncBuffer->m_pBuffer);  
  241.                 delete pAsyncBuffer->m_pAsyncFileData;  
  242.                 delete [] pAsyncBuffer->m_pBuffer;  
  243.                 delete pAsyncBuffer;  
  244.                 pAsyncBuffer = NULL;  
  245.   
  246.                 // 其它逻辑  
  247.                 Sleep(1000);  
  248.                 break;  
  249.             }     
  250.         }// end while 2  
  251.       
  252.     } //  end while 1  
  253.   
  254.     s_mutexRequent.release();  
  255.     s_mutexFileContent.release();  
  256. #ifdef WINOS  
  257.     CloseHandle(s_loadingThread);  
  258. #else  
  259.     // 设置了pthread_detach(s_loadingThread),退出时会自动释放,  
  260.     // 否则需要pthread_join()等待可结合的线程终止被释放它的栈寄存器资源.  
  261. #endif  
  262.     return 0;    
  263. }    


版权声明:本文为博主原创文章,转载请注明出处http://blog.youkuaiyun.com/blues1021。 https://blog.youkuaiyun.com/Blues1021/article/details/44523169
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值