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 */