http://blog.csdn.net/guosha/article/details/3136721
版权声明:本文为博主原创文章,未经博主允许不得转载。
在多线程的程序中,多线程间一般使用mutex对临界区进行互斥。但这依赖于各线程的协同约定为进入临界区前都必须加锁,而退出临界区前必须解锁,只要其中的一个线程不遵循这个约定就无法做到互斥一致。比如一个函数:
- int func()
- {
- a++;
- retrun a;
- }
要对这个函数进行保护,可以这样做:
- lock(mutex);
- ret = func();
- unlock(mutex);
但更好的做法是直接在函数内部进行保护,如下:
- int func()
- {
- int b;
- lock(mutex);
- a++;
- b = a;
- unlock(mutex);
- return b;
- }
这样函数提供了自保护,就保证了只要调用这个接口就肯定是协同一致的。
一般来说,编程时都约定对一个加上的锁必须由加锁线程本身去解锁。但事实测试发现,对普通锁,一个线程可以去解另一个线程的加上的锁。测试代码如下:
- #include <stdio.h>
- #include <unistd.h>
- #include <pthread.h>
- #include <stdlib.h>
- pthread_mutex_t tMutex = PTHREAD_MUTEX_INITIALIZER;
- void *ThreadFun(void *ptr)
- {
- pthread_t tid;
- int i = *((int *)ptr);
- int ret;
- tid = pthread_self();
- pthread_detach(tid);
- if ((i % 2) == 0)
- {
- printf("[%u] try to lock mutex!/n", tid);
- ret = pthread_mutex_lock(&tMutex);
- if (ret == 0)
- {
- printf("[%u] lock mutex sucess!/n", tid);
- }
- else
- {
- printf("[%u] lock mutex failed!/n", tid);
- }
- }
- else
- {
- printf("[%u] try to unlock mutex!/n", tid);
- ret = pthread_mutex_unlock(&tMutex);
- if (ret == 0)
- {
- printf("[%u] unlock mutex sucess!/n", tid);
- }
- else
- {
- printf("[%u] unlock mutex failed!/n", tid);
- }
- }
- sleep(10);
- printf("[%u] exit!/n", tid);
- }
- int main(int argc, char *argv[])
- {
- pthread_t tid;
- int ret;
- int i;
- for (i = 0; i < atoi(argv[1]); i++)
- {
- ret = pthread_create(&tid, NULL, ThreadFun, &i);
- if (ret != 0)
- {
- strerror(ret);
- return 0;
- }
- sleep(1);
- }
- while(1);
- return 0;
- }
编译执行结果如下:
[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 同一线程可重加锁,解锁一次生效 所有等待锁的线程自由竞争