【问题标题】:Parent process runs twice after receiving signal父进程收到信号后运行两次
【发布时间】:2013-12-29 21:52:34
【问题描述】:

我写了一个程序,父进程打印出从参数列表接收到的 5 个(彩票)号码。然后子进程生成5个随机数,如果其中一个数等于参数,则向父进程发送SIGUSR1,否则发送SIGUSR2信号。 如果我不使用信号,只需打印孩子的答案,代码就可以正常工作。但是有了这些信号,父进程运行了两次,或者至少它的内容被打印了两次。你能向我解释一下这种行为吗?提前致谢!

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> 
#include <sys/wait.h> 
#include <errno.h> 
#include <signal.h>

void handler(int signumber){
        printf("The child got a hit, my pid: %i\n", getpid());
}

void handler2(int signumber){
        printf("The child had no hit!\n");
}

int main(int argc, char* argv[])
{
    signal(SIGUSR1,handler);
    signal(SIGUSR2,handler2);

    int status, child;
    int num1 = atoi(argv[1]);
    int num2 = atoi(argv[2]);
    int num3 = atoi(argv[3]);
    int num4 = atoi(argv[4]);
    int num5 = atoi(argv[5]);

    if ( num1<0 || num1>45 || num2<0 || num2>45 || num3<0 || num3>45 || num4<0 || num4>45 || num5<0 || num5>45 ){
        perror("We need 5 numbers in range of 0 and 45");
        exit(1);
    }

    child = fork();

    if(child>0){ //parent
        printf("The numbers: %i, %i, %i, %i, %i. my pid: %i \n", num1,num2,num3,num4,num5,getpid());
    } else{
        int rnd,i,isAnyHit;
        isAnyHit = 0;
        srand(time(NULL) * (getpid())); 
        for ( i=0;i<5;i++ ){
            rnd = ((rand()%45)+1);
            if ( rnd == num1 || rnd == num2 || rnd == num3 || rnd == num4 || rnd == num5 ){
                kill(getppid(),SIGUSR1);
                isAnyHit++;
            }   
        }
        if ( isAnyHit == 0 )
            kill(getppid(),SIGUSR2);
    }
    return 0; 
}

【问题讨论】:

  • 如果匹配多个号码会怎样?如果所有 5 个数字都匹配正确,您可能会发送 SIGUSR1 5 次?
  • 如果您告诉我们哪条消息被重复,将会有所帮助。此外,如果您将消息翻译成英文(那是什么语言?匈牙利语?),我们会更容易阅读代码。奇怪的一件事是你没有让你的父母等待孩子,所以当你到达孩子的 kill(getppid(), ...) 时,你的父母很可能已经退出,你的进程已经被继承通过 init 进程,您正在向 init 发送信号(希望您不是以 root 身份执行此操作!)
  • 可能是父级的 printf 被信号中断,两个并发的 printf 混淆了一些数据结构。如果您将printf("Szülő: A lottó számok: %i, %i, %i, %i, %i. A pid számom: %i \n", num1,num2,num3,num4,num5,getpid()); 替换为pause();,会起作用吗?通常,C 信号处理程序只需要更改 volatile 变量即可。

标签: c operating-system signals fork


【解决方案1】:

我做了一些代码更改,它似乎对我有用。

#include <stdio.h>    
#include <stdlib.h>    
#include <unistd.h>     
#include <sys/wait.h>     
#include <errno.h>     
#include <signal.h>    
#include <time.h>    


void handler(int signumber){    
  printf("Got signal %d at %i\n", signumber, getpid());    
}    

int main(int argc, char* argv[])    
{    
  signal(SIGUSR1,handler);    
  signal(SIGUSR2,handler);    

  int status, child;    
  int num1 = atoi(argv[1]);    
  int num2 = atoi(argv[2]);    
  int num3 = atoi(argv[3]);    
  int num4 = atoi(argv[4]);    
  int num5 = atoi(argv[5]);    

  if ( num1<0 || num1>45 || num2<0 || num2>45 || num3<0 || num3>45 || num4<0 || num4>45 || num5<0 || num5>45 ){    
    perror("Invalid numbers\n");    
    exit(1);    
  }    

  child = fork();    

  if(child>0){ //szülő    
    printf("In the parent - child pid is %i, parent pid is %i\n", child, getpid());    
    sleep(1000);    
  } else{    
    printf("In the child - child pid is %i, parent pid is %i\n", getpid(), getppid());    
    int rnd,i,isAnyHit;    
    isAnyHit = 0;    
    srand(time(NULL) * (getpid()));     
    for ( i=0;i<5;i++ ){    
      rnd = ((rand()%45)+1);    
      printf("Checking %i against numbers\n", rnd);    
      if ( rnd == num1 || rnd == num2 || rnd == num3 || rnd == num4 || rnd == num5)){    
        printf("Matched %i\n", rnd);    
        kill(getppid(),SIGUSR1);    
        isAnyHit++;    
      }       
    }    
    if ( isAnyHit == 0 )    
      kill(getppid(),SIGUSR2);    
  }    

  printf("PID %i is ending\n", getpid());    
  return 0;     
}  

以下输出:

$ ./a.out 1 2 3 4 5
In the parent - child pid is 20401, parent pid is 20400
In the child - child pid is 20401, parent pid is 20400
Checking 6 against numbers
Checking 18 against numbers
Checking 15 against numbers
Checking 42 against numbers
Checking 4 against numbers
Matched 4
PID 20401 is ending
Got signal 10 at 20400
PID 20400 is ending

但如果两个数字匹配:

$ ./a.out 1 2 3 4 5
In the parent - child pid is 20493, parent pid is 20492
In the child - child pid is 20493, parent pid is 20492
Checking 2 against numbers
Matched 2
Checking 5 against numbers
Matched 5
Checking 13 against numbers
Got signal 10 at 20492
Checking 36 against numbers
Checking 19 against numbers
Got signal 10 at 20492
PID 20493 is ending
PID 20492 is ending

我得到 2 个 SIGUSR1 (10)。

【讨论】:

  • 您的代码存在睡眠被信号中断的问题,因此父进程将 a) 如果没有匹配项,则将睡眠整整 1000 秒,b) 在第一次匹配后退出。而不是睡眠,最好使用int rc; while(wait(&amp;rc)==-1) ; 之类的东西来等待孩子退出并通过重新启动系统调用来处理等待的中断。
  • 糟糕。如果没有匹配,父母应该至少得到一个 SIGUSR2,所以别再睡 1000 秒了。
  • 是的 - 在这种情况下,睡眠是无关紧要的。我只是添加了它,因为当我测试时,父母在收到任何信号之前就死了。我忘了是秒,还以为是毫秒,所以我用了 1000。
  • 耶稣,我意识到这是 /n 在我打印父进程中的数字后,如果我删除它,就像你在这个版本中所做的那样,缓冲区是空的,所以它不会我猜是在到达另一个 printf 时再写一次。我会接受这个作为答案,至少你帮我弄清楚了,谢谢大家的时间!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多