找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 4091|回复: 1

用C++实现多线程Mutex锁 |chexlong

[复制链接]
发表于 2011-12-8 10:00:50 | 显示全部楼层 |阅读模式
  本文目的:用C++和Windows的互斥对象(Mutex)来实现线程同步锁。
    准备知识:1,内核对象互斥体(Mutex)的工作机理,WaitForSingleObject函数的用法,这些可以从MSDN获取详情; 2,当两个或更多线程需要同时访问一个共享资源时,系统需要使用同步机制来确保一次只有一个线程使用该资源。Mutex 是同步基元,它只向一个线程授予对共享资源的独占访问权。如果一个线程获取了互斥体,则要获取该互斥体的第二个线程将被挂起,直到第一个线程释放该互斥体。
    下边是我参考开源项目C++ Sockets的代码,写的线程锁类
Lock.h
  1. #ifndef _Lock_H
  2. #define _Lock_H
  3. #include <windows.h>
  4. //锁接口类
  5. class IMyLock
  6. {
  7. public:
  8.         virtual ~IMyLock() {}
  9.         virtual void Lock() const = 0;
  10.         virtual void Unlock() const = 0;
  11. };
  12. //互斥对象锁类
  13. class Mutex : public IMyLock
  14. {
  15. public:
  16.         Mutex();
  17.         ~Mutex();
  18.         virtual void Lock() const;
  19.         virtual void Unlock() const;
  20. private:
  21.         HANDLE m_mutex;
  22. };
  23. //锁
  24. class CLock
  25. {
  26. public:
  27.         CLock(const IMyLock&);
  28.         ~CLock();
  29. private:
  30.         const IMyLock& m_lock;
  31. };
  32. #endif
  33. Lock.cpp#include "Lock.h"
  34. //创建一个匿名互斥对象
  35. Mutex::Mutex()
  36. {
  37.         m_mutex = ::CreateMutex(NULL, FALSE, NULL);
  38. }
  39. //销毁互斥对象,释放资源
  40. Mutex::~Mutex()
  41. {
  42.         ::CloseHandle(m_mutex);
  43. }
  44. //确保拥有互斥对象的线程对被保护资源的独自访问
  45. void Mutex::Lock() const
  46. {
  47.         DWORD d = WaitForSingleObject(m_mutex, INFINITE);
  48. }
  49. //释放当前线程拥有的互斥对象,以使其它线程可以拥有互斥对象,对被保护资源进行访问
  50. void Mutex::Unlock() const
  51. {
  52.         ::ReleaseMutex(m_mutex);
  53. }
  54. //利用C++特性,进行自动加锁
  55. CLock::CLock(const IMyLock& m) : m_lock(m)
  56. {
  57.         m_lock.Lock();
  58. }
  59. //利用C++特性,进行自动解锁
  60. CLock::~CLock()
  61. {
  62.         m_lock.Unlock();
  63. }
复制代码

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

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



    如果将测线程函数中的代码注视掉,重新编译代码,运行
CLock lock(g_Lock);
     则结果见下图



    由此可见,通过使用Mutex的封装类,即可达到多线程同步的目的。因Mutex属于内核对象,所以在进行多线程同步时速度会比较慢,但是用互斥对象可以在不同进程的多个线程之间进行同步。
    在实际应用中,我们通常还会用到关键代码段CRITICAL_SECTION,在下篇博客中,我将会把关键代码段锁添加进来,并且对Mutex和CRITICAL_SECTION的性能做以比较。

作者:chexlong 发表于2011-12-7 20:38:57 原文链接
发表于 2011-12-14 09:30:35 | 显示全部楼层
CRITICAL_SECTION会先自旋2000次再调用内核对象,BOOST库用内核对象实现了类似CRITICAL_SECTION的锁,那代码还是值得看看。
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-12-22 18:32 , Processed in 0.016986 second(s), 6 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表