缘由
有为同学在- http://blog.csdn.net/zy825316/article/details/21390199
- 我是初级学习UNIX的,我看了好久没懂,程序清单12-2中指出的retry函数因为被安排为原子操作而函数内进行加锁。retry内加锁是不是想让里面的操作粒度更细?还有如果我另外为retry创建一个互斥量,是不是最初的那个互斥量可以不指定为递归的?谢谢
第一个问题
其实我不太懂什么叫操作粒度更细。但是我想说这段代码并没有完整的实现,包括retry函数自身也没有实现,但书中说说清楚了:并且把retry函数安排为原子操作
原子操作我相信都懂,所以我们只需要认为retry函数就需要原子操作就可以了。为什么需要?我也不知道,因为没完整实现。书上只是为了这个讲清递归锁而做了一个假设而已。现在就假设retry函数需要原子操作。
第二个问题
我认为简单说来该例子就是能不能不用递归锁,使用两个互斥量。 答案是不能。原因一
这个12-2程序实例之前,作者已经说了:程序清单12-2解释了有必要使用递归互斥锁的另一种情况
看中文的书可能有点误解,我们来看看英文:
的解释通常认为是必要的(给人一种最好这样做,但是不必须的感觉),但是我认为此处应该是必须的。可以看看该词更多的解释。
原因二
举一个反例子。首先做一点准备工作。
改写一点点程序12-2源码的main一点点部分,就是抽取条件判断单做一个方法:
int main(void){
int err,condition,arg;
struct timespec when;
if((err=pthread_mutexattr_init(&attr))!=0){
err_exit(err,"pthread_mutexattr_init failed");
}
if((err=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE))!=0){
err_exit(err,"can't set recuresive type");
}
if((err=phread_mutex_init(&mutex,&attr))!=0){
err_exit(err,"can't create recursive mutex");
}
condition();
exit(0);
}
void condition(){
/*...*/
pthread_mutex_lock(&mutex);
/*...*/
if(condition){
/*calculate target time "when" */
timeout(&when,retry,(void *)arg);
}
/*...*/
pthread_mutex_unlock(&mutex);
/*...*/
}
好的,那么一切正常运行。那么我设定retry函数内调用condition方法:
void retry(void *arg){
pthread_mutex_lock(&mutex);
/*其他代码*/
condition();
/*其他执行步骤*/
pthread_mutex_unlock(&mutex);
}
可能有人觉得很荒唐,我觉得没什么,因为这就是业务或者逻辑的需要,就是需要我再次调用condition函数,我也没办法。
好的,准备工作做完后我们来看一下。
如果像哪位同学所说的使用两个互斥量会发生什么事呢? 会发生死锁。
暂且称condition()内的为mutex,retry()内的为mutex2,流程如下:
- 执行main()
- 执行condition():第一次加锁mutex1
- 执行timeout()
- 执行timeout()的最后一句:(*func)(arg); (假设发生了这样的情况)
- 执行retry(void *arg):第一次加锁mutex2
- 又执行condition():第二次加锁mutex1
- 发生死锁。
死锁原因
为什么会发生死锁呢。书上已经说的很清楚了。我的linux操作系统,我还专门做了实验,实验代码如下:
/**
* 这是一个测试:linux下默认情况时,对同一个锁加锁两次,会导致死锁
* author:zy
*/
#include <pthread.h>
#include <stdio.h>
pthread_mutexattr_t attr;
pthread_mutex_t mutex;
int main(void){
pthread_mutex_init(&mutex,&attr);
//同一个线程对一个锁加第一次
pthread_mutex_lock(&mutex);
printf("1\n");
//同一个线程对同一个锁加锁第二次
pthread_mutex_lock(&mutex);
/*由于死锁下面的函数永远不会执行*/
printf("2\n");
pthread_mutex_unlock(&mutex);
printf("3\n");
return 0;
}
运行结果:
asd@asd-desktop:~/workspace/test/src$ ./a.out
1