我正在尝试使用System V信号量来实现条件variables。 为了简单起见,我们假设一次只有一个进程可以等待一个条件variables。 这个概念看起来很简单,所以只要看看我的互斥和条件variables包装的实现,其中:
这里是:
//Sets value of 'num' semaphore from 'semid' semaphore set to be 'val'. // Returns 0 on success and -1 on failure. int set_value(int semid, int num, int val) { union semun setval_semun; setval_semun.val = val; return semctl(semid, num, SETVAL, setval_semun); } // Returns the value of semaphore 'num' from 'semid' semaphore set // or -1 on failure. int get_value(int semid, int num) { return semctl(semid, num, GETVAL); } // Locks 'mutex'. Returns 0 on success and 1 if 'mutex' is invalid. // Returns -1 on other error. int lock_mutex(int semid, int mutex) { struct sembuf op; if (get_value(semid, mutex) > 1) return 1; op.sem_num = mutex; op.sem_op = -1; op.sem_flg = 0; return semop(semid, &op, 1); } // Unlocks 'mutex'. Returns 0 on success and 1 ig the 'mutex' isn't locked. // Returns -1 on different error. int unlock_mutex(int semid, int mutex) { struct sembuf op; if (get_value(semid, mutex) != 0) return 1; op.sem_num = mutex; op.sem_op = 1; op.sem_flg = 0; return semop(semid, &op, 1); } // Waits on condition 'cond' and frees 'mutex'. // Returns 0 on success and 1 if either some other process is waiting on 'cond' // or 'mutex' is not locked. Returns -1 on other failure. int wait_cond(int semid, int cond, int mutex) { struct sembuf ops[2]; if (get_value(semid, cond) != 0 || get_value(semid, mutex) != 0) return 1; ops[0].sem_num = cond; ops[0].sem_op = 1; ops[0].sem_flg = 0; semop(semid, ops, 1); ops[0].sem_num = mutex; ops[0].sem_op = 1; ops[0].sem_flg = 0; ops[1].sem_num = cond; ops[1].sem_op = 0; ops[1].sem_flg = 0; return semop(semid, ops, 2); } // Wakes up process waiting for 'cond'. Returns 0 on success. Returns 1 when // no process is waiting for 'cond' and -1 on other error. int wake_cond(int semid, int cond) { struct sembuf op; if (semctl(semid, cond, GETVAL) != 1) return 1; op.sem_num = cond; op.sem_op = -1; op.sem_flg = 0; return semop(semid, &op, 1); }
现在看看我的最小testing程序。 它由两个共享两个信号量的进程组成。 一个用作互斥体,另一个用作条件variables。 他们都有相同的stream量:
如果我把这件事情弄清楚,他们应该交替做一些事情。
int main(int argc, char** argv) { key_t key = 0; pid_t pid = 0; int semid = 0; int const mutex = 0; int const cond = 1; int repeat = 5; char const* name = NULL; union semun setval_semun; // Create unique key. key = get_unique_key(argv[0], 47); if (key == -1) return 1; // Create and intialize semaphore set. semid = semget(key, 2, 0666 | IPC_CREAT); if (semid == -1) return 1; if (set_value(semid, mutex, 1) != 0 || set_value(semid, cond, 1) != 0) { semctl(semid, 0, IPC_RMID); return 1; } // Fork. pid = fork(); if (fork() < 0) return 1; else if(pid > 0) name = "parent"; else name = " child"; while(repeat--) { printf("%s: (0), mutex: %d, cond: %d, repeat: %d\n", name, get_value(semid, mutex), get_value(semid, cond), repeat); if (lock_mutex(semid, mutex) != 0) return 1; sleep(1); printf("%s: (1), mutex: %d, cond: %d, repeat: %d\n", name, get_value(semid, mutex), get_value(semid, cond), repeat); if (wake_cond(semid, cond) != 0) return 1; printf("%s: (2), mutex: %d, cond: %d, repeat: %d\n", name, get_value(semid, mutex), get_value(semid, cond), repeat); if (repeat == 0) { if (unlock_mutex(semid, mutex) != 0) return 1; } else if (wait_cond(semid, cond, mutex) != 0) return 1; printf("%s: (3), mutex: %d, cond: %d, repeat: %d\n", name, get_value(semid, mutex), get_value(semid, cond), repeat); } //Wait for child and clear resources. if (pid > 0) { wait(NULL); semctl(semid, 0, IPC_RMID); } return 0; }
这是我得到的输出,这是疯狂的奇怪:
parent: (0), mutex: 1, cond: 1, repeat: 4 parent: (0), mutex: 0, cond: 1, repeat: 4 child: (0), mutex: 0, cond: 1, repeat: 4 child: (0), mutex: 0, cond: 1, repeat: 4 parent: (1), mutex: 0, cond: 1, repeat: 4 parent: (2), mutex: 0, cond: 0, repeat: 4 ^C
特别要看前两行。 他们告诉你,通知号(0)在while循环的相同运行中以不同的值被打印两次! 它的结果是僵局,所以我^ C它。
不要担心get_unique_key()函数 – 它只是它的名字所说的。
任何帮助,使这项工作或解释奇怪的输出将不胜感激。 谢谢。