我正在尝试使用System V信号量实现条件变量。为简单起见,我们假设一次只有一个进程可以等待一个条件变量。这个概念看起来很简单,所以只需看看我的互斥和条件变量包装器的实现,其中:
这就是:
//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);
}
现在查看我的最小测试程序。它由两个共享两个信号量的进程组成。一个用作互斥量,另一个用作条件变量。他们都有相同的流程:
如果我把这一切都弄好了,他们应该交替做'某事'。
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循环的同一次运行中打印了两次,具有不同的值!对于cource来说,它最终会陷入僵局,所以我就这样了。
不要担心get_unique_key()函数 - 它只是它的名字。
任何帮助完成这项工作或解释奇怪的输出将不胜感激。谢谢。