zoukankan      html  css  js  c++  java
  • CRITICAL_SECTION同步易出错的地方

    众所周知通过CRITICAL_SECTION可以对多个线程同步,然而加锁和解锁的次数不匹配将导致死锁:

    1. class CLock  
    2. {  
    3. public:  
    4.     CLock()  
    5.     {  
    6.         InitializeCriticalSection(&m_cs);  
    7.     }  
    8.   
    9.     ~CLock()  
    10.     {  
    11.         DeleteCriticalSection(&m_cs);  
    12.     }  
    13.   
    14.     void Lock()  
    15.     {  
    16.         EnterCriticalSection(&m_cs);  
    17.     }  
    18.   
    19.     void Unlock()  
    20.     {  
    21.         LeaveCriticalSection(&m_cs);  
    22.     }  
    23. private:  
    24.     CRITICAL_SECTION    m_cs;  
    25. };  
    1. int _tmain(int argc, _TCHAR* argv[])  
    2. {  
    3.     unsigned ThreadId1, ThreadId2;  
    4.     HANDLE  hThread1, hThread2;  
    5.     hThread1 = (HANDLE)_beginthreadex(0, 0, ThreadFun, NULL, 0, &ThreadId1);  
    6.     Sleep(1000);  
    7.     hThread2 = (HANDLE)_beginthreadex(0, 0, ThreadFun, NULL, 0, &ThreadId2);  
    8.   
    9.     getchar();  
    10.   
    11.     InterlockedCompareExchange(&gExit, 1, gExit);  
    12.     WaitForSingleObject(hThread1, -1);  
    13.     WaitForSingleObject(hThread2, -1);  
    14.   
    15.     return 0;  
    16. }  


    1、线程A加锁两次、解锁一次,将导致线程B一直不能获得锁:


    1. long gExit = 0;  
    2. CLock gLock;  
    3.   
    4. unsigned int _stdcall ThreadFun(void* argv)  
    5. {  
    6.     while (true)  
    7.     {  
    8.         gLock.Lock();  
    9.         gLock.Lock();  
    10.         if (InterlockedCompareExchange(&gExit, gExit, 0))  
    11.         {  
    12.             return 0;  
    13.             gLock.Unlock();  
    14.         }  
    15.   
    16.         printf("Thread(%d) is Running ", GetCurrentThreadId());  
    17.   
    18.         gLock.Unlock();  
    19.         //gLock.Unlock();  
    20.   
    21.         Sleep(100);  
    22.     }  
    23. }  


    2、线程A加锁一次,解锁两次,当线程A下次再试图获得锁,将不能获取的到陷入死等,也将导致死锁,同理线程B。:


    1. unsigned int _stdcall ThreadFun(void* argv)  
    2. {  
    3.     while (true)  
    4.     {  
    5.         // 加锁一次  
    6.         gLock.Lock();  
    7.         //gLock.Lock();  
    8.         if (InterlockedCompareExchange(&gExit, gExit, 0))  
    9.         {  
    10.             return 0;  
    11.             gLock.Unlock();  
    12.         }  
    13.   
    14.         printf("Thread(%d) is Running ", GetCurrentThreadId());  
    15.   
    16.         // 解锁两次,下次gLock.Lock()将陷入死等  
    17.         gLock.Unlock();  
    18.         gLock.Unlock();  
    19.   
    20.         Sleep(100);  
    21.     }  
    22. }  


    3、解决,可以定义一个自动获得锁,保证加锁和解锁完全匹配:

    1. class AutoLock  
    2. {  
    3. public:  
    4.     AutoLock()  
    5.     {  
    6.         m_lock.Lock();  
    7.     }  
    8.     ~AutoLock()  
    9.     {  
    10.         m_lock.Unlock();  
    11.     }  
    12.   
    13. private:  
    14.     CLock   m_lock;  
    15.   
    16. private:  
    17.     AutoLock(const AutoLock& lock);  
    18.     AutoLock& operator=(const AutoLock& lock);  
    19. };  
    1. unsigned int _stdcall ThreadFun(void* argv)  
    2. {  
    3.     while (true)  
    4.     {  
    5.         AutoLock auto_lock;  
    6.         if (InterlockedCompareExchange(&gExit, gExit, 0))  
    7.         {  
    8.             return 0;  
    9.         }  
    10.   
    11.         printf("Thread(%d) is Running ", GetCurrentThreadId());  
    12.   
    13.         Sleep(100);  
    14.     }  
    15. }  

    4、后记:以上是最简单的锁实现,加锁和解锁往往导致效率低下,以此改进,使用读写锁、闩锁等不同的加锁粒度来提升性能。
  • 相关阅读:
    Educational Codeforces Round 64(ECR64)
    [网络流]BZOJ4657 tower 最小割约束
    009:JSON
    008:数据类型
    007:MySQL SSL
    006:多实例安装
    005: 存储引擎介绍
    004:MySQL数据库体系结构
    003:MySQL账号创建授权以及Workbench
    002:MySQL升级以及访问连接
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13318558.html
Copyright © 2011-2022 走看看