用C++实现多线程Mutex锁(Win32)

原作者:chexlong 原文地址:http://blog.csdn.net/chexlong/article/details/7051193

本文目的:用C++和Windows的互斥对象(Mutex)来实现线程同步锁。

    准备知识:1,内核对象互斥体(Mutex)的工作机理,WaitForSingleObject函数的用法,这些可以从MSDN获取详情; 2,当两个或更多线程需要同时访问一个共享资源时,系统需要使用同步机制来确保一次只有一个线程使用该资源。Mutex 是同步基元,它只向一个线程授予对共享资源的独占访问权。如果一个线程获取了互斥体,则要获取该互斥体的第二个线程将被挂起,直到第一个线程释放该互斥体。

    下边是我参考开源项目C++ Sockets的代码,写的线程锁类

Lock.h

  1. #ifndef _Lock_H  
  2. #define _Lock_H  
  3.   
  4. #include <windows.h>  
  5.   
  6. //锁接口类  
  7. class IMyLock  
  8. {  
  9. public:  
  10.     virtual ~IMyLock() {}  
  11.   
  12.     virtual void Lock() const = 0;  
  13.     virtual void Unlock() const = 0;  
  14. };  
  15.   
  16. //互斥对象锁类  
  17. class Mutex : public IMyLock  
  18. {  
  19. public:  
  20.     Mutex();  
  21.     ~Mutex();  
  22.   
  23.     virtual void Lock() const;  
  24.     virtual void Unlock() const;  
  25.   
  26. private:  
  27.     HANDLE m_mutex;  
  28. };  
  29.   
  30. //锁  
  31. class CLock  
  32. {  
  33. public:  
  34.     CLock(const IMyLock&);  
  35.     ~CLock();  
  36.   
  37. private:  
  38.     const IMyLock& m_lock;  
  39. };  
  40.   
  41.   
  42. #endif  

Lock.cpp

  1. #include "Lock.h"  
  2.   
  3. //创建一个匿名互斥对象  
  4. Mutex::Mutex()  
  5. {  
  6.     m_mutex = ::CreateMutex(NULL, FALSE, NULL);  
  7. }  
  8.   
  9. //销毁互斥对象,释放资源  
  10. Mutex::~Mutex()  
  11. {  
  12.     ::CloseHandle(m_mutex);  
  13. }  
  14.   
  15. //确保拥有互斥对象的线程对被保护资源的独自访问  
  16. void Mutex::Lock() const  
  17. {  
  18.     DWORD d = WaitForSingleObject(m_mutex, INFINITE);  
  19. }  
  20.   
  21. //释放当前线程拥有的互斥对象,以使其它线程可以拥有互斥对象,对被保护资源进行访问  
  22. void Mutex::Unlock() const  
  23. {  
  24.     ::ReleaseMutex(m_mutex);  
  25. }  
  26.   
  27. //利用C++特性,进行自动加锁  
  28. CLock::CLock(const IMyLock& m) : m_lock(m)  
  29. {  
  30.     m_lock.Lock();  
  31. }  
  32.   
  33. //利用C++特性,进行自动解锁  
  34. CLock::~CLock()  
  35. {  
  36.     m_lock.Unlock();  
  37. }  

    下边是测试代码

  1. // MyLock.cpp : 定义控制台应用程序的入口点。  
  2. //  
  3.   
  4. #include <iostream>  
  5. #include <process.h>  
  6. #include "Lock.h"  
  7.   
  8. using namespace std;  
  9.   
  10. //创建一个互斥对象  
  11. Mutex g_Lock;  
  12.   
  13.   
  14. //线程函数  
  15. unsigned int __stdcall StartThread(void *pParam)  
  16. {  
  17.     char *pMsg = (char *)pParam;  
  18.     if (!pMsg)  
  19.     {  
  20.         return (unsigned int)1;  
  21.     }  
  22.   
  23.     //对被保护资源(以下打印语句)自动加锁  
  24.     //线程函数结束前,自动解锁  
  25.     CLock lock(g_Lock);  
  26.   
  27.     for( int i = 0; i < 5; i++ )  
  28.     {  
  29.         cout << pMsg << endl;  
  30.         Sleep( 500 );  
  31.     }  
  32.   
  33.     return (unsigned int)0;  
  34. }  
  35.   
  36. int main(int argc, char* argv[])  
  37. {  
  38.     HANDLE hThread1, hThread2;  
  39.     unsigned int uiThreadId1, uiThreadId2;  
  40.   
  41.     char *pMsg1 = "First print thread.";  
  42.     char *pMsg2 = "Second print thread.";  
  43.   
  44.     //创建两个工作线程,分别打印不同的消息  
  45.   
  46.     //hThread1 = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StartThread, (void *)pMsg1, 0, (LPDWORD)&uiThreadId1);  
  47.     //hThread2 = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StartThread, (void *)pMsg2, 0, (LPDWORD)&uiThreadId2);  
  48.   
  49.     hThread1 = (HANDLE)_beginthreadex(NULL, 0, &StartThread, (void *)pMsg1, 0, &uiThreadId1);  
  50.     hThread2 = (HANDLE)_beginthreadex(NULL, 0, &StartThread, (void *)pMsg2, 0, &uiThreadId2);  
  51.   
  52.     //等待线程结束  
  53.     DWORD dwRet = WaitForSingleObject(hThread1,INFINITE);  
  54.     if ( dwRet == WAIT_TIMEOUT )  
  55.     {  
  56.         TerminateThread(hThread1,0);  
  57.     }  
  58.     dwRet = WaitForSingleObject(hThread2,INFINITE);  
  59.     if ( dwRet == WAIT_TIMEOUT )  
  60.     {  
  61.         TerminateThread(hThread2,0);  
  62.     }  
  63.   
  64.     //关闭线程句柄,释放资源  
  65.     ::CloseHandle(hThread1);  
  66.     ::CloseHandle(hThread2);  
  67.   
  68.     system("pause");  
  69.     return 0;  
  70. }  

    用VC2005编译,启动程序,下边是截图

技术分享

 

    如果将测线程函数中的代码注视掉,重新编译代码,运行

  1. CLock lock(g_Lock);  

     则结果见下图

技术分享

 

    由此可见,通过使用Mutex的封装类,即可达到多线程同步的目的。因Mutex属于内核对象,所以在进行多线程同步时速度会比较慢,但是用互斥对象可以在不同进程的多个线程之间进行同步。

    在实际应用中,我们通常还会用到临界区,也有叫做关键代码段的CRITICAL_SECTION,在下篇博客中,我将会把CRITICAL_SECTION锁添加进来,并且对Mutex和CRITICAL_SECTION的性能做以比较。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。