使用 SystemV 信号量 API,我可以等待给定信号量为零(或增加),但我没有找到与 POSIX API 类似的任何内容。
让我解释一下上下文。
我有一个
master
进程,它分叉并执行 N 个其他 child
进程。所以进程总数是N+1
。每个进程(主进程 + 子进程)都有一个 init()
步骤,每个人都将等待,这样一旦每个人都完成了 init()
步骤,N+1
进程就可以运行其余的执行。
用 SystemV 术语来说,我是这样做的:
void wait_zero(int sem_id, int sem_index) {
// ...
struct sembuf sops;
sops.sem_num = sem_index;
sops.sem_op = 0; // <-- this is what makes the process wait on a zero value
sops.sem_flg = 0;
int res = semop(sem_id, &sops, 1);
// ...
}
void acquire(int sem_id, int sem_index) {
// ...
struct sembuf sops;
sops.sem_num = sem_index;
sops.sem_op = -1;
sops.sem_flg = 0;
int res = semop(sem_id, &sops, 1);
// ...
}
现在,假设我将
sync_semaphore
的值设置为N+1
,则每个进程都可以依次执行该信号量的获取和零等待:
// ...
int main(int argc, char **argv) {
// obtain sync_semaphore id
init();
acquire(sync_semaphore); // decrements sync_semaphore
wait_zero(sync_semaphore); // waits for it to be zero before proceeding
// rest of the execution...
}
// ...
在 POSIX 中,我可以将信号量的初始值设置为非负值。然后我可以执行
sem_wait()
(减 1)和 sem_push()
(加 1),但我等不及信号量为零。
我似乎找不到与 POSIX 类似的东西。有没有什么方法可以在不进行任何形式的忙碌等待的情况下实现相同的效果?这个问题与waiting for a condition to be true
有关,所以我确信某些东西一定存在,但我丢失了一些东西并且找不到与我的问题类似的东西。
我的猜测是,这个确切的问题无法单独使用 POSIX 信号量来解决,因为它们的 API 是如何工作的(也许使用信号或其他东西来实现一些魔法?)。
我还想补充一点,使用 SystemV 对我来说并不是什么大不了的事,我只是好奇这里是否缺少一些东西。
我尝试考虑在共享内存中创建一个变量,初始化为
N+1
(进程总数)的值,然后使用信号量,每个进程都会递减其值并仅在以下情况下使用pause()
暂停其执行: value > 0
,否则它会向每个暂停的进程发出信号以恢复执行。这个解决方案应该可行,但对于使用 SystemV API 轻松完成的事情来说有点麻烦
在 POSIX [...] 中我等不及信号量为零。事实上,POSIX 信号量不支持该功能。它们具有比 Sys V 信号量更简单、更精简的 API,但功能更少。
有没有什么方法可以达到同样的效果,而无需任何形式的忙碌等待?当然。条件变量和互斥锁的组合就像同步工具中的瑞士军刀,可以很容易地用来构建屏障。在这种情况下,您还需要一个共享计数器。
或者,您可以使用两个信号量和(再次)共享计数器构建屏障,如
使用信号量实现 N 进程屏障(不特定于操作系统)的第一个答案中所述。这与您的想法类似,但更聪明一点,因为它不需要程序记住障碍物的初始高度。