Linux System V Semaphore semget多进程同时创建缺陷解决方法

System V Semaphore的创建过程缺陷是创建与赋初值由两个函数完成,这会导致两个进程同时创建的话会出现竞争和不一致状态,即使是使用了IPC-EXCL标记。

示例:

 1 oflag = IPC-CREAT | IPC-EXCL | SVSEM-MODE;
 2 if ( (semid = semget (key, 1, oflag) ) >= 0) {
     /* success, we are the first, so initialize */
 3     arg.val = 1;
 4     semctl (semid, 0, SETVAL, arg) ;
 
 5 } else if (errno == EEXIST) {
     /* already exists, just open */
 6     semid = semget(key, 1, SVSEM-MODE);
 
 7 } else
 8     err-sys("semget error");
 
 9 semop(semid, ... ) ; /* decrement the semaphore by 1 */

第一个创建进程可能执行语句1,2,3进行创建,而第二个进程创建失败,执行1,2,5,6,9。即第二个进程在第一个进程虽然创建成功但是还没来得及赋初值(第4行)时,已经被第二个进程拿去用了,而其获取的初值是未定义的,所以第14行的操作也就是未定义的。

一种改进方法是,循环查询semid_ds中的成员sem_otime,它在sem创建成功后是0,然后记录sem被执行的上一次操作的时间。通过判断sem_otime不为0即可知道sem已经初始化完成。

示例:

1 oflag = IPC-CREAT | IPC-EXCL | SVSEM-MODE;
2 if ( (semid = semget (key, 1, oflag) ) >= 0) {
       /* success, we are the first, so initialize */
3     arg.val = 1;
4     semctl (semid, 0, SETVAL, arg) ;
  
5 else if (errno == EEXIST) {
     /* someone else has created; make sure it's initialized */
6    semid = semget(Ftok(L0CK-PATH, 0). 1, SVSEM-MODE);
7    arg.buf = &seminfo;
8    for (i = 0; i < MAX-TRIES; i++) (
9        semctl(semid, 0, IPC-STAT, arg);
10       if(arg.buff->sem_otime!=0) //判断初始化已经被另一个进程完成。
11           goto init;
12       sleep (1) ;
13   }
14    err-quit("semget OK, but semaphore not initialized");
15 } else
16      err-sys("semget error");
 
17 semop(semid, ... ) ; /* decrement the semaphore by 1 */    
原文地址:https://www.cnblogs.com/NerdWill/p/5006739.html