IPC信号量中的UNDO问题
更新日期:
什么是信号信号量
为了防止出现多个程序同时访问一个共享资源而引发的一系列问题,我们用信号量来授权,在任一时刻只能有一个执行线程访问代码的临界区,临界区是指执行数据更新的代码需要独占式地执行。
信号量是一个特殊的变量,程序对其访问都是原子操作,且只允许对他进行等待(P)和发送(V)信息操作。
信号量的工作原理
由于信号量只能进行两种操作等待和发送信号,如下:
P(sv) :如果sv的值大于零,就给他减一;如果它的值为零,就挂起该进程的执行
V(sv) :如果有其他进程因等待sv而被挂起,就让他恢复,如果没有进程因等待sv而挂起就给他加1.
sem_undo数据结构
以往使用信号量的情形通常都是用于进程间互斥,锁定临界区。信号量还是比文件锁有优势的,效率不是高那么一点,起码不用打开文件关闭文件这些耗时的工作。但是信号量最大的一个问题就是一旦锁定,若在解锁之前出现程序崩溃等segment fault问题,将直接导致锁定的信号量无法恢复,形成永久占用。文件锁则没有这个问题,进程的退出将导致文件描述符关闭,在该描述符上进行的锁定操作就自行解除了。
好在设计者们已经考虑了这个问题,在加锁的时候回有一个UNDO的设置,也就是在调用semop的时候指定操作结构体当中可以放置一个UNDO参数,调用方式如下:
semop(sem_id, &lock_sem, 1);
其中sem就是定义的一个操作结构体,一般定义为:
static struct sembuf lock_sem = {
0, -1, SEM_UNDO
};
static struct sembuf unlock_sem = {
0, 1, SEM_UNDO
};
sembuf结构定义如下:
struct sembuf{
short sem_num;//除非使用一组信号量,否则它为0
short sem_op;//信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,即P(等待)操作,
//一个是+1,即V(发送信号)操作。
short sem_flg;//通常为SEM_UNDO,使操作系统跟踪信号,
//并在进程没有释放该信号量而终止时,操作系统释放信号量
};
这样的UNDO选项会让内核记录一个与调用进程相关的UNDO记录,如果该进程崩溃,则根据这个进程的UNDO记录自动恢复相应信号量的计数值。