各种Mutex的使用与区别

http://blog.csdn.net/guosha/article/details/3136721

在多线程的程序中,多线程间一般使用mutex对临界区进行互斥。但这依赖于各线程的协同约定为进入临界区前都必须加锁,而退出临界区前必须解锁,只要其中的一个线程不遵循这个约定就无法做到互斥一致。比如一个函数:

  1. int func()
  2. {
  3.      a++;
  4.      retrun a;
  5. }

要对这个函数进行保护,可以这样做:

  1. lock(mutex);
  2. ret = func();
  3. unlock(mutex);

但更好的做法是直接在函数内部进行保护,如下:

  1. int func()
  2. {
  3.     int b;
  4.     lock(mutex);
  5.     a++;
  6.     b = a;
  7.     unlock(mutex);
  8.     return b; 
  9. }

这样函数提供了自保护,就保证了只要调用这个接口就肯定是协同一致的。

 

一般来说,编程时都约定对一个加上的锁必须由加锁线程本身去解锁。但事实测试发现,对普通锁,一个线程可以去解另一个线程的加上的锁。测试代码如下:

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <pthread.h>
  4. #include <stdlib.h>
  5. pthread_mutex_t tMutex = PTHREAD_MUTEX_INITIALIZER;
  6. void *ThreadFun(void *ptr)
  7. {
  8.     pthread_t tid;
  9.     int i = *((int *)ptr);
  10.     int ret;
  11.     tid = pthread_self();
  12.     pthread_detach(tid);
  13.     if ((i % 2) == 0)
  14.     {   
  15.         printf("[%u] try to lock mutex!/n", tid);
  16.         ret = pthread_mutex_lock(&tMutex);
  17.         if (ret == 0)
  18.         {
  19.             printf("[%u] lock mutex sucess!/n", tid);
  20.         }
  21.         else
  22.         {
  23.             printf("[%u] lock mutex failed!/n", tid);
  24.         }
  25.     }   
  26.     else
  27.     {   
  28.         printf("[%u] try to unlock mutex!/n", tid);
  29.         ret = pthread_mutex_unlock(&tMutex);
  30.         if (ret == 0)
  31.         {
  32.             printf("[%u] unlock mutex sucess!/n", tid);
  33.         }
  34.         else
  35.         {
  36.             printf("[%u] unlock mutex failed!/n", tid);
  37.         }
  38.     }
  39.     sleep(10);
  40.     printf("[%u] exit!/n", tid);
  41. }
  42. int main(int argc, char *argv[])
  43. {
  44.     pthread_t tid;
  45.     int ret;
  46.     int i;
  47.     for (i = 0; i < atoi(argv[1]); i++)
  48.     {
  49.         ret = pthread_create(&tid, NULL, ThreadFun, &i);
  50.         if (ret != 0)
  51.         {
  52.             strerror(ret);
  53.             return 0;
  54.         }
  55.         sleep(1);
  56.     }
  57.     while(1);
  58.     return 0;
  59. }

编译执行结果如下:           
[root@localhost mutexlock]# gcc -D_GNU_SOURCE -o mutex mutex.c -lpthread
[root@localhost mutexlock]# ./mutex 10&
[1] 5165
[root@localhost mutexlock]# [3086166944] try to lock mutex!
[3086166944] lock mutex sucess!
[3075677088] try to unlock mutex!
[3075677088] unlock mutex sucess!
[3065187232] try to lock mutex!
[3065187232] lock mutex sucess!
[3054697376] try to unlock mutex!
[3054697376] unlock mutex sucess!
[3044207520] try to lock mutex!
[3044207520] lock mutex sucess!
[3033717664] try to unlock mutex!
[3033717664] unlock mutex sucess!
[3023227808] try to lock mutex!
[3023227808] lock mutex sucess!
[3012737952] try to unlock mutex!
[3012737952] unlock mutex sucess!
[3002248096] try to lock mutex!
[3002248096] lock mutex sucess!
[2991758240] try to unlock mutex!
[2991758240] unlock mutex sucess!

从上可见,对普通互斥锁,其它线程可以去解另一个线程加上的锁。

如果你想有一种锁强制本线程加上的锁只能由本线程来解的话就可以使用纠错锁,把上面的程序稍微改一下就可以验证纠错锁的特性:

pthread_mutex_t tMutex = PTHREAD_MUTEX_INITIALIZER;
改成
pthread_mutex_t tMutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
编译执行结果如下:
[root@localhost mutexlock]# gcc -D_GNU_SOURCE -o mutex mutex.c -lpthread
[root@localhost mutexlock]# ./mutex 10&
[1] 5226
[root@localhost mutexlock]# [3086744480] try to lock mutex!
[3086744480] lock mutex sucess!
[3076254624] try to unlock mutex!
[3076254624] unlock mutex failed!
[3065764768] try to lock mutex!
[3055274912] try to unlock mutex!
[3055274912] unlock mutex failed!
[3044785056] try to lock mutex!
[3034295200] try to unlock mutex!
[3034295200] unlock mutex failed!
[3023805344] try to lock mutex!
[3013315488] try to unlock mutex!
[3013315488] unlock mutex failed!
[3002825632] try to lock mutex!
[2992335776] try to unlock mutex!
[2992335776] unlock mutex failed!

从上可见,对纠错锁,线程不能去解另一个线程加上的锁。

另外还有递归锁跟自适应锁,这四个锁之间的区别如下:
锁类型  初始化方式                       加解锁特征                              调度特征
普通锁  PTHREAD_MUTEX_INITIALIZER     同一线程可重复加锁,解锁一次释放锁     先等待锁的进程先获得锁
嵌套锁   PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP    同一线程可重复加锁,解锁同样次数才可释放锁    先等待锁的进程先获得锁
纠错锁   PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP   同一线程不能重复加锁,加上的锁只能由本线程解锁  先等待锁的进程先获得锁
自适应锁 PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP     同一线程可重加锁,解锁一次生效      所有等待锁的线程自由竞争 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值