APUE: 12-2程序清单 使用递归锁 处:能不能不用递归锁? P321

缘由

有为同学在
  • http://blog.csdn.net/zy825316/article/details/21390199
给我留了问题:

  • 我是初级学习UNIX的,我看了好久没懂,程序清单12-2中指出的retry函数因为被安排为原子操作而函数内进行加锁。retry内加锁是不是想让里面的操作粒度更细?还有如果我另外为retry创建一个互斥量,是不是最初的那个互斥量可以不指定为递归的?谢谢
其实我也是初学unix,但我想了很久该如何回答。所以故此记录一下。由于有两个问号,我认为有两个问题
 

第一个问题

其实我不太懂什么叫操作粒度更细。但是我想说这段代码并没有完整的实现,包括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,流程如下:
  1. 执行main()
  2. 执行condition():第一次加锁mutex1
  3. 执行timeout()
  4. 执行timeout()的最后一句:(*func)(arg);  (假设发生了这样的情况)
  5. 执行retry(void *arg):第一次加锁mutex2
  6. 又执行condition():第二次加锁mutex1
  7. 发生死锁。
但是使用 递归互斥锁就不会


死锁原因

为什么会发生死锁呢。书上已经说的很清楚了。

我的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

总结

我刚开始也很犹豫是能不能不用递归互斥锁,看了英文版才下了决心认为是这个例子是必须要用递归锁,所以在想反例,这个反例貌似有点勉强,这是因为用了大量的假设,但是我认为这些假设在业务要求的时候还是有可能发生的。呼,我也期待高手讲解一下。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值