• 【转】互斥对象锁和临界区锁性能比较


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

      在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、因互斥对象锁属于内核对象,所以在进行多线程同步时速度会比较慢,但是可以在不同进程的多个线程之间进行同步。

  • 相关阅读:
    GridView中checkbox实现全选[转]
    go 格式化秒 running
    mysql 聚簇索引和非聚簇索引 running
    go context上下文取消 running
    go reflect running
    time.ticker running
    go 数据结构与算法之二分查找 running
    mysql 联合索引最左前缀匹配原则 running
    es 修改 mapping 字段类型 running
    linux 查看虚拟机网卡命令 running
  • 原文地址:https://www.cnblogs.com/gkwang/p/4482940.html
Copyright © 2020-2023  润新知