这里就APUE的12.4节同步属性的实例做自己的读书记录
现在,我们需要将一套只支持单线程的库,修改为支持多线程。因为已经有应用程序已经使用了这个库,所以我们无法修改库中函数的接口。否则原来的应用程序将无法运行。
并且假设我们的库中只有两个函数,函数的参数是一个结构体x:
1. void func1(x)
2. void func2(x)
以上2个函数的调用逻辑是:func1 会调用 func2
书上一共说明了3种修改的方式,这3种方式的限制条件,书中原话是:“只有在为该数据结构提供了分配函数时才可行”。
个人的理解是(如有错误还望指出,谢谢!),我们的应用程序很可能会创建该对象,而我们又不提供对象的构造函数,而允许应用程序使用如下方式创建对象,那么,我们在需要在数据结构中添加新数据(互斥锁)就会使应用程序出错。
struct X{
int num;
}
X x;
如果我们提供类似 struct X* CreateX(int num)的分配函数,那么我们就可以在这个函数中初始化新加入的数据结构。
3种修改的方式为:
1. 使用递归锁
优点:能够处理复杂的调用逻辑,代码简洁
缺点:递归锁的使用需要一定技巧,它只应在没有其他可行方案的情况下使用(书上没有说明是什么技巧,我也没有这方面的经验,如果有知道的朋友还望指点一二)
2. 库中的函数如果调用其他的库函数,那么在调用之前先释放互斥量,调用其他库函数时再次获取互斥量
优点:避免使用递归锁
缺点:例如,func1函数中调用func2。在调用func2之前func1释放互斥量,进入func2时再次获得互斥量。在释放和再次获得互斥量之间存在一个时间窗口。这给其他线程提供修改数据结构(x)的机会。一旦数据结构在这个时间窗口中被修改,那么可能(具体情况取决于互斥量试图提供什么样的保护)产生问题。
3. 提供库函数的私有版本
优点:避免使用递归锁
缺点:无法处理复杂的逻辑。书中的原话是“例如库需要调用库以外的函数,而且可能会再次回调库中的函数时,就需要依赖递归锁”。
我的理解是: 例如,func3是一个库以外的函数,该函数也会调用func2。那么如果 func1 像书中描述的那样,在使用函数私有化版本调用完 func2_locked后,又会调用func3,那么就会出现该死的死锁了。
阅读(533) | 评论(0) | 转发(0) |