zoukankan      html  css  js  c++  java
  • 线程同步--递归锁和非递归锁【转】

    本文转载自:http://blog.csdn.net/yusiguyuan/article/details/21560079

    一、简介

    1.1 进程/线程同步方法

          常见的进程/线程同步方法有互斥锁(或称互斥量Mutex)、读写锁(rdlock)、条件变量(cond)、信号量(Semophore)等。

          在windows系统中,临界区(Critical Section)和事件对象(Event)也是常用的同步方法。

    1.2 递归锁/非递归锁

          Mutex可以分为递归锁(recursive mutex)和非递归锁(non-recursive mutex)。 递归锁也叫可重入锁(reentrant mutex),非递归锁也叫不可重入锁(non-reentrant mutex)。

          二者唯一的区别是:

                同一个线程可以多次获取同一个递归锁,不会产生死锁。

                如果一个线程多次获取同一个非递归锁,则会产生死锁。

          Windows下的Mutex和Critical Section是可递归的。 

          Linux下的pthread_mutex_t锁是默认是非递归的。可以通过设置PTHREAD_MUTEX_RECURSIVE属性,将pthread_mutex_t锁设置为递归锁。

    二、代码

    2.1 Critical Section递归锁

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. #include <Windows.h>  
    2. #include <iostream>  
    3. #include <string>  
    4.   
    5. int counter = 0;  
    6.   
    7. CRITICAL_SECTION g_cs;  
    8.   
    9. void doit(void* arg)  
    10. {  
    11.     int i, val;  
    12.     for (i=0; i<5000; i++)  
    13.     {  
    14.         EnterCriticalSection(&g_cs);  
    15.         EnterCriticalSection(&g_cs);  
    16.   
    17.         val = counter;  
    18.         printf("thread %d : %d ", int(arg), val+1);  
    19.         counter = val + 1;  
    20.   
    21.         LeaveCriticalSection(&g_cs);  
    22.         LeaveCriticalSection(&g_cs);  
    23.     }  
    24. }  
    25.   
    26. int main(int argc, char*argv[])  
    27. {  
    28.     InitializeCriticalSection(&g_cs);  
    29.   
    30.     HANDLE hThread1 = CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)doit, (void*)1, 0, NULL);  
    31.     HANDLE hTrehad2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)doit, (void*)2, 0, NULL);  
    32.   
    33.     WaitForSingleObject(hThread1, INFINITE);  
    34.     WaitForSingleObject(hTrehad2, INFINITE);  
    35.   
    36.     DeleteCriticalSection(&g_cs);  
    37.   
    38.       
    39.     return 0;  
    40. }  


    结果:加1次锁和2次锁,均可以正确的输出1~10000。

    2.2 pthread_mutex_t非递归锁

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. #include <stdio.h>  
    2. #include <stdlib.h>  
    3. #include <pthread.h>  
    4.   
    5. int counter = 0;  
    6.   
    7. pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;  
    8.   
    9. void* doit(void*)  
    10. {  
    11.         int i, val;  
    12.         for (i=0; i<5000; i++)  
    13.         {  
    14.                 pthread_mutex_lock(&g_mutex);  
    15.                 pthread_mutex_lock(&g_mutex);  
    16.   
    17.                 val = counter;  
    18.                 printf("%x: %d ", pthread_self(), val+1);  
    19.                 counter = val + 1;  
    20.   
    21.                 pthread_mutex_unlock(&g_mutex);  
    22.                 pthread_mutex_unlock(&g_mutex);        
    23.         }  
    24. }  
    25.   
    26. int main(int argc, char*argv[])  
    27. {  
    28.         pthread_t tid1, tid2;  
    29.   
    30.         pthread_create(&tid1, NULL, doit, NULL);  
    31.         pthread_create(&tid2, NULL, doit, NULL);  
    32.   
    33.         pthread_join(tid1, NULL);  
    34.         pthread_join(tid2, NULL);  
    35.   
    36.         return 0;  
    37. }  

    结果:加1次锁,可以正确的输出1~10000;加2次锁,死锁,不输出任何信息。

    2.3 pthread_mutex_t递归锁(PTHREAD_MUTEX_RECURSIVE)

    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. #include <stdio.h>  
    2. #include <stdlib.h>  
    3. #include <pthread.h>  
    4.   
    5. int counter = 0;  
    6.   
    7. pthread_mutex_t g_mutex;// = PTHREAD_MUTEX_INITIALIZER;  
    8.   
    9. void* doit(void*)  
    10. {  
    11.         int i, val;  
    12.         for (i=0; i<5000; i++)  
    13.         {  
    14.                 pthread_mutex_lock(&g_mutex);  
    15.                 pthread_mutex_lock(&g_mutex);  
    16.   
    17.                 val = counter;  
    18.                 printf("%x: %d ", pthread_self(), val+1);  
    19.                 counter = val + 1;  
    20.   
    21.                 pthread_mutex_unlock(&g_mutex);  
    22.                 pthread_mutex_unlock(&g_mutex);  
    23.         }  
    24. }  
    25.   
    26. int main(int argc, char*argv[])  
    27. {  
    28.         //create recursive attribute  
    29.         pthread_mutexattr_t attr;  
    30.         pthread_mutexattr_init(&attr);  
    31.   
    32.         //set recursive attribute  
    33.         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);  
    34.   
    35.         pthread_mutex_init(&g_mutex, &attr);  
    36.   
    37.   
    38.         pthread_t tid1, tid2;  
    39.         pthread_create(&tid1, NULL, doit, NULL);  
    40.         pthread_create(&tid2, NULL, doit, NULL);  
    41.   
    42.         pthread_join(tid1, NULL);  
    43.         pthread_join(tid2, NULL);  
    44.   
    45.   
    46.         pthread_mutex_destroy(&g_mutex);  
    47.   
    48.         //destroy recursive attribute  
    49.         pthread_mutexattr_destroy(&attr);  
    50.   
    51.         return 0;  
    52. }  

    结果:加1次锁和2次锁,均可以正确的输出1~10000。、

    在线程同步中,使用锁是一种非常常见的做法,尽量使用非递归锁,避免使用递归锁!

    非递归锁的逻辑清晰,在出现死锁的时候可以轻松DEBUG!仅凭着一点就需要使用非递归锁!

  • 相关阅读:
    交换实验
    路由引入和控制
    ISIS
    BGP联盟
    BGP2
    bgp
    Linux日常总结
    配置本地yum源方法
    达梦数据库常见问题-安装
    达梦数据库常见问题-安装
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/5774051.html
Copyright © 2011-2022 走看看