zoukankan      html  css  js  c++  java
  • (转)互斥对象锁和临界区锁性能比较 .

    在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

  • 相关阅读:
    Mybatis里Mapper.xml加强
    在eclipse中怎么把一个普通的项目变成一个maven项目
    给自己写博客定的小标准
    五一假期的惬意生活~
    MAC上postman离线安装时提示加载扩展程序出错怎么办?
    2017-4-6 四月生花,冷暖自知
    微信小程序开发过程中tabbar页面显示的相关问题及解决办法!
    微信小程序中如何实现分页下拉加载?(附源码)
    利用stylist插件,简单两步屏蔽新浪微博上的广告
    微信小程序官方指南手册,教你如何使用微信小程序!
  • 原文地址:https://www.cnblogs.com/wonderKK/p/2549478.html
Copyright © 2011-2022 走看看