C 叉子上的打印错误

C 叉子上的打印错误,c,linux,printf,fork,semaphore,C,Linux,Printf,Fork,Semaphore,我为我的英语道歉,希望你能理解。 因此,我的程序中有一个printf的问题,它在父亲结束时等待,在printf之前等待。所以我总是让父亲打印他的所有信息,然后儿子打印他的所有信息,而信息应该被划掉 从我所看到的,我读到,我必须有一个flush,但它不能解决我的问题。 谢谢你的帮助。 这是我的密码 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait

我为我的英语道歉,希望你能理解。 因此,我的程序中有一个printf的问题,它在父亲结束时等待,在printf之前等待。所以我总是让父亲打印他的所有信息,然后儿子打印他的所有信息,而信息应该被划掉

从我所看到的,我读到,我必须有一个flush,但它不能解决我的问题。 谢谢你的帮助。 这是我的密码

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <unistd.h>
#include <sys/shm.h>

int cpt = 0;

void fils(int *cpt){
  int i;
  for(i = 0; i < 3; i++){
    (*cpt)++;
    printf("son : %d\n", *cpt);
  }
}

void pere(int *cpt){
  int i;
  for(i = 0; i < 3; i++){
    (*cpt)--;
    printf("father : %d\n", *cpt);
    fflush(stdout);
  }
}

int main (int argc, char*argv[]){
  key_t key;
  int memShared;
  int *cpt = NULL;

  key = ftok(argv[0],'p');
  memShared = shmget(key, sizeof(int), IPC_CREAT|IPC_EXCL|0666);
  cpt = shmat ( memShared, cpt, 0);
  *cpt = 0;

  fflush(stdout);
  switch (fork()){
    case -1: perror("erreur de création du fils");
         exit(99);
    case  0: fils(cpt);
         exit(1);
    default: pere(cpt);
         wait(NULL);
  }
   shmctl(memShared, IPC_RMID, NULL);

  return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int-cpt=0;
无效文件(内部*cpt){
int i;
对于(i=0;i<3;i++){
(*cpt)++;
printf(“子:%d\n”,*cpt);
}
}
无效pere(整数*cpt){
int i;
对于(i=0;i<3;i++){
(*cpt)--;
printf(“父亲:%d\n”,*cpt);
fflush(stdout);
}
}
int main(int argc,char*argv[]){
钥匙(t)钥匙;;
int memShared;
int*cpt=NULL;
key=ftok(argv[0],'p');
memShared=shmget(键,sizeof(int),IPC|u CREAT | IPC|u EXCL | 0666);
cpt=shmat(memShared,cpt,0);
*cpt=0;
fflush(stdout);
开关(fork()){
案例1:perror(“法院的审查”);
出口(99);
案例0:fils(cpt);
出口(1);
默认值:pere(cpt);
等待(空);
}
shmctl(memShared,IPC_RMID,NULL);
返回0;
}
我总是把这个放在候机楼里

父亲:-1 父亲:-1 父亲:-2 儿子:0 儿子:-1 儿子:0

我认为它应该被划掉例如父亲:-1儿子:0父亲:-1。。。
谢谢你的帮助。

这是一场经典的比赛。要实现“儿子优先”顺序,只需在
开关中重新排列您的行即可:

switch (fork()){
case -1: perror("erreur de création du fils");
     exit(99);
case  0: fils(cpt);
     exit(1);
default: wait(NULL); //First - wait
     pere(cpt);      //Then - print   
}
您无法保证这种简单的解决方案是否会如您所愿工作。您想要的是确保流程只执行一个循环迭代,直到它被关闭

如果您想确保它们以这种
abababab
方式运行,那么您需要另一种同步机制。请记住,简单的信号量是不够的。您可能需要一个管道或fifo队列来允许此进程通信。查找名为
pipe
mkfifo
的函数。然后你可以这样做:

for(number_of_iterations)
{
   wait for a message from the other process;
   do work on shm;
   send message to another process, allowing it to continue;
}
这将激发一种代币的概念

至于评论中的建议:将fork结果保留在变量a中,然后使用
waitpid
等待,当您有更多进程时会更安全,因为
wait
等待第一个结束的进程,而不是特定的进程

chenchongyf1@chenchongyf1:~$
chenchongyf1@chenchongyf1:~$ ./wrong_printf
father : -1
son : 0
son : 1
son : 2
father : 1
father : 0
chenchongyf1@chenchongyf1:~$** 

这个程序在我的电脑上运行。我的意思是,父亲的printf和儿子的printf确实是交叉的。

你说“应该交叉”,但你没有实现任何机制来做到这一点。两个进程都在竞相写入它们的所有输出,程序中没有任何东西让一个进程等待另一个进程。如果您想让他们交替输出,您必须编写代码让他们这样做。您也没有同步对共享内存的访问,这就是为什么您会得到奇怪的输出,就像父亲在一行中写入两个
-1
一样。您始终需要将
fork
的结果保存在一个变量中,因为父亲需要它来执行
waitpid
。另请参见和@BasileStarynkevitch:不必要。他正在等待任何一个子进程完成。这已经足够有选择性了。(我们不是在一般情况下,我们真的需要使用
waitpid
)@PaulGriffiths:嗨,谢谢你的回答。当我说“交叉”时,我的意思是我们永远不知道父亲或儿子中的哪一个会先运行,所以我认为父亲或儿子可以运行2次迭代和printf,然后儿子可以运行1次迭代,这样我们就可以得到交叉。这就是我说的候补人选。但是是的,你是对的,我忘了同步对共享内存的访问,我现在就纠正它!我已经更新了我的答案,以便更准确地回答你的问题。没关系。该程序可能有效,但不能保证有效。这通常是比赛中的一个问题。