你有一个竞争条件。
当主进程执行sem_post 时,它会[快速] 循环并且[几乎] 立即执行下一个 sem_wait 并在子进程有机会获得信号量之前获取信号量。
简单/天真的解决方案是在每个循环的底部添加一个小usleep:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <semaphore.h>
int
main()
{
sem_t *sem;
setlinebuf(stdout);
sem = sem_open("share", O_CREAT, 0, 1);
sem_unlink("share");
int i;
if (fork()) {
for (i = 0; i < 10; i++) {
sem_wait(sem);
printf("Hello world\n");
sem_post(sem);
usleep(10);
}
wait(NULL);
}
else {
for (i = 0; i < 10; i++) {
sem_wait(sem);
printf("Bonjour monde\n");
sem_post(sem);
usleep(10);
}
}
return 0;
}
现在的输出是:
Hello world
Bonjour monde
Hello world
Bonjour monde
Hello world
Bonjour monde
Hello world
Bonjour monde
Hello world
Bonjour monde
Hello world
Bonjour monde
Hello world
Bonjour monde
Hello world
Bonjour monde
Hello world
Bonjour monde
Hello world
Bonjour monde
更新:
如下所述,两个信号量解决方案更好,因为它保证了交替:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <semaphore.h>
int
main()
{
sem_t *sempar;
sem_t *semcld;
setlinebuf(stdout);
sem_unlink("parent");
sempar = sem_open("parent", O_CREAT, 0, 1);
// by blocking child semaphore, this guarantees parent starts first
sem_unlink("child");
semcld = sem_open("child", O_CREAT, 0, 0);
int i;
if (fork()) {
for (i = 0; i < 10; i++) {
sem_wait(sempar);
printf("Hello world (%d)\n",i);
sem_post(semcld);
}
wait(NULL);
}
else {
for (i = 0; i < 10; i++) {
sem_wait(semcld);
printf("Bonjour monde (%d)\n",i);
sem_post(sempar);
}
}
return 0;
}
更新 #2:
但输出不是随机的,它先打印 HelloWorld,然后再打印 Bonjour 并重复。
好的,那么单信号量解决方案是更好的解决方案,但有一些修改:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <sys/wait.h>
#include <semaphore.h>
sem_t *sem;
void
doloop(time_t seed,const char *msg)
{
int i;
int rval;
srand(seed);
for (i = 0; i < 30; i++) {
rval = rand() % 100000;
sem_wait(sem);
printf("%s i=%d rval=%d\n",msg,i,rval);
sem_post(sem);
usleep(rval);
}
}
int
main()
{
time_t seed;
setlinebuf(stdout);
sem_unlink("share");
sem = sem_open("share", O_CREAT, 0, 1);
seed = time(NULL);
if (fork()) {
doloop(seed,"Hello World");
wait(NULL);
}
else {
doloop(seed ^ ~0,"Bonjour monde");
}
return 0;
}