CRITICAL_SECTION同步易出错的地方

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

[cpp]  view plain copy
  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. };  
[cpp]  view plain copy
  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一直不能获得锁:


[cpp]  view plain copy
  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\n", GetCurrentThreadId());  
  17.   
  18.         gLock.Unlock();  
  19.         //gLock.Unlock();  
  20.   
  21.         Sleep(100);  
  22.     }  
  23. }  


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


[cpp]  view plain copy
  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\n", GetCurrentThreadId());  
  15.   
  16.         // 解锁两次,下次gLock.Lock()将陷入死等  
  17.         gLock.Unlock();  
  18.         gLock.Unlock();  
  19.   
  20.         Sleep(100);  
  21.     }  
  22. }  


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

[cpp]  view plain copy
  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. };  
[cpp]  view plain copy
  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\n", GetCurrentThreadId());  
  12.   
  13.         Sleep(100);  
  14.     }  
  15. }  

4、后记:以上是最简单的锁实现,加锁和解锁往往导致效率低下,以此改进,使用读写锁、闩锁等不同的加锁粒度来提升性能。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值