(转)互斥对象锁和临界区锁性能比较 .

在Win32平台上进行多线程编程,常会用到锁。下边用C++实现了互斥对象(Mutex)锁和临界区(CRITICAL_SECTION)锁,以加深理解和今后方便使用。代码已在VS2005环境下编译测试通过。

Lock.h

  1. #ifndef _Lock_H   
  2. #define _Lock_H   
  3.   
  4. #include <windows.h>   
  5.   
  6.   
  7. //锁接口类   
  8. class ILock  
  9. {  
  10. public:  
  11.     virtual ~ILock() {}  
  12.   
  13.     virtual void Lock() const = 0;  
  14.     virtual void Unlock() const = 0;  
  15. };  
  16.   
  17. //互斥对象锁类   
  18. class Mutex : public ILock  
  19. {  
  20. public:  
  21.     Mutex();  
  22.     ~Mutex();  
  23.   
  24.     virtual void Lock() const;  
  25.     virtual void Unlock() const;  
  26.   
  27. private:  
  28.     HANDLE m_mutex;  
  29. };  
  30.   
  31. //临界区锁类   
  32. class CriSection : public ILock  
  33. {  
  34. public:  
  35.     CriSection();  
  36.     ~CriSection();  
  37.   
  38.     virtual void Lock() const;  
  39.     virtual void Unlock() const;  
  40.   
  41. private:  
  42.     CRITICAL_SECTION m_critclSection;  
  43. };  
  44.   
  45.   
  46. //锁   
  47. class CMyLock  
  48. {  
  49. public:  
  50.     CMyLock(const ILock&);  
  51.     ~CMyLock();  
  52.   
  53. private:  
  54.     const ILock& m_lock;  
  55. };  
  56.   
  57.   
  58. #endif  

Lock.cpp

  1. #include "Lock.h"   
  2.   
  3. //---------------------------------------------------------------------------   
  4.   
  5. //创建一个匿名互斥对象   
  6. Mutex::Mutex()  
  7. {  
  8.     m_mutex = ::CreateMutex(NULL, FALSE, NULL);  
  9. }  
  10.   
  11. //销毁互斥对象,释放资源   
  12. Mutex::~Mutex()  
  13. {  
  14.     ::CloseHandle(m_mutex);  
  15. }  
  16.   
  17. //确保拥有互斥对象的线程对被保护资源的独自访问   
  18. void Mutex::Lock() const  
  19. {  
  20.     DWORD d = WaitForSingleObject(m_mutex, INFINITE);  
  21. }  
  22.   
  23. //释放当前线程拥有的互斥对象,以使其它线程可以拥有互斥对象,对被保护资源进行访问   
  24. void Mutex::Unlock() const  
  25. {  
  26.     ::ReleaseMutex(m_mutex);  
  27. }  
  28.   
  29. //---------------------------------------------------------------------------   
  30.   
  31. //初始化临界资源对象   
  32. CriSection::CriSection()  
  33. {  
  34.     ::InitializeCriticalSection(&m_critclSection);  
  35. }  
  36.   
  37. //释放临界资源对象   
  38. CriSection::~CriSection()  
  39. {  
  40.     ::DeleteCriticalSection(&m_critclSection);  
  41. }  
  42.   
  43. //进入临界区,加锁   
  44. void CriSection::Lock() const  
  45. {  
  46.     ::EnterCriticalSection((LPCRITICAL_SECTION)&m_critclSection);  
  47. }     
  48.   
  49. //离开临界区,解锁   
  50. void CriSection::Unlock() const  
  51. {  
  52.     ::LeaveCriticalSection((LPCRITICAL_SECTION)&m_critclSection);  
  53. }  
  54.   
  55. //---------------------------------------------------------------------------   
  56.   
  57. //利用C++特性,进行自动加锁   
  58. CMyLock::CMyLock(const ILock& m) : m_lock(m)  
  59. {  
  60.     m_lock.Lock();  
  61. }  
  62.   
  63. //利用C++特性,进行自动解锁   
  64. CMyLock::~CMyLock()  
  65. {  
  66.     m_lock.Unlock();  
  67. }  


    下边是测试代码

  1. // MyLock.cpp : 定义控制台应用程序的入口点。   
  2. //   
  3.   
  4. #include <iostream>   
  5. #include <process.h>   
  6. #include <time.h>   
  7. #include "Lock.h"   
  8.   
  9. using namespace std;  
  10.   
  11.   
  12. #define ENABLE_MUTEX   
  13. #define ENABLE_CRITICAL_SECTION   
  14.   
  15.   
  16. #if defined (ENABLE_MUTEX)   
  17.   
  18. //创建一个互斥对象类型锁   
  19. Mutex g_Lock;  
  20.   
  21. #elif defined (ENABLE_CRITICAL_SECTION)   
  22.   
  23. //创建一个临界区类型锁   
  24. CriSection g_Lock;  
  25.   
  26. #endif   
  27.   
  28.   
  29. void LockCompare(int &iNum)  
  30. {  
  31.     CMyLock lock1(g_Lock);  
  32.   
  33.     iNum++;  
  34. }  
  35.   
  36.   
  37. //线程函数   
  38. unsigned int __stdcall StartThread(void *pParam)  
  39. {  
  40.     char *pMsg = (char *)pParam;  
  41.     if (!pMsg)  
  42.     {  
  43.         return (unsigned int)1;  
  44.     }  
  45.   
  46.     CMyLock lock2(g_Lock);  
  47.   
  48.     clock_t tStart,tEnd;  
  49.   
  50.     tStart = clock();  
  51.   
  52.     int iNum = 0;  
  53.     for (int i = 0; i < 100000; i++)  
  54.     {  
  55.         LockCompare(iNum);  
  56.     }  
  57.       
  58.     tEnd = clock();  
  59. #if defined (ENABLE_MUTEX)   
  60.   
  61.     cout<<"The lock type is mutex, time = "<<(tEnd - tStart)<<" ms."<<endl;  
  62.   
  63. #elif defined (ENABLE_CRITICAL_SECTION)   
  64.   
  65.     cout<<"The lock type is critical section, time = "<<(tEnd - tStart)<<" ms."<<endl;  
  66.   
  67. #endif   
  68.   
  69.     return (unsigned int)0;  
  70. }  
  71.   
  72. int main(int argc, char* argv[])  
  73. {  
  74.     HANDLE hThread1, hThread2;  
  75.     unsigned int uiThreadId1, uiThreadId2;  
  76.   
  77.     char *pMsg1 = "First print thread.";  
  78.     char *pMsg2 = "Second print thread.";  
  79.   
  80.     //创建两个工作线程,分别打印不同的消息   
  81.     hThread1 = (HANDLE)_beginthreadex(NULL, 0, &StartThread, (void *)pMsg1, 0, &uiThreadId1);  
  82.     hThread2 = (HANDLE)_beginthreadex(NULL, 0, &StartThread, (void *)pMsg2, 0, &uiThreadId2);  
  83.   
  84.     //等待线程结束   
  85.     DWORD dwRet = WaitForSingleObject(hThread1,INFINITE);  
  86.     if ( dwRet == WAIT_TIMEOUT )  
  87.     {  
  88.         TerminateThread(hThread1,0);  
  89.     }  
  90.     dwRet = WaitForSingleObject(hThread2,INFINITE);  
  91.     if ( dwRet == WAIT_TIMEOUT )  
  92.     {  
  93.         TerminateThread(hThread2,0);  
  94.     }  
  95.   
  96.     //关闭线程句柄,释放资源   
  97.     ::CloseHandle(hThread1);  
  98.     ::CloseHandle(hThread2);  
  99.   
  100.     system("pause");  
  101.     return 0;  
  102. }  


    在线程函数StartThread中,循环100000次,对保护资源“iNum ”反复加锁,解锁。编译,运行5次,将每次打印的线程锁切换耗时时间记录下来。之后,将测试代码中的宏 #define ENABLE_MUTEX 注释掉,禁掉互斥锁,启用临界区锁,重新编译代码,运行5次。下边是分别是互斥锁和临界区锁耗时记录(不同机器上耗时会不同):

 

互斥锁

 

线程Id

耗时 / ms

总计

1

141

125

125

125

125

641

2

140

125

140

125

156

686

 

 

临界区锁

 

线程Id

耗时 / ms

总计

1

15

16

31

31

31

124

2

31

31

31

16

31

140

 

 

 

    互斥锁总共耗时:641+686=1327 ms,而临界区锁:124+140=264 ms。显而易见,临界区锁耗时比互斥锁耗时节约了大概5倍的时间。

    总结:1、在同一个进程的多线程同步锁,宜用临界区锁,它比较节约线程上下文切换带来的系统开销。但因临界区工作在用户模式下,所以不能对不同进程中的多线程进行同步。2、因互斥对象锁属于内核对象,所以在进行多线程同步时速度会比较慢,但是可以在不同进程的多个线程之间进行同步。

 转自:http://blog.csdn.net/chexlong/article/details/7060425

posted @ 2012-06-14 16:11  ☆A希亿  阅读(591)  评论(0编辑  收藏  举报