C 信号处理器没有';t形手柄信号

C 信号处理器没有';t形手柄信号,c,linux,process,signals,fork,C,Linux,Process,Signals,Fork,我有一个家庭作业,我应该写一个C程序来生成一个孩子。父级打开一个文件,并通过读取每一行、打印行号和行内容,然后倒带文件来永久循环 子进程以随机间隔向父进程发送SIGUSR1信号。为了创造这些间歇时间,我选择让孩子睡觉 当收到第一个信号时,父级跳过打印语句。当接收到另一个SIGUSR1信号时,它再次开始打印。它一直持续到随机数目的信号被发送为止。然后它忽略了五个信号。忽略五个信号后,父进程打印接收到的信号数,并在接收到一个以上的信号后退出 我的问题是,当信号从子进程发送时,程序崩溃。父进程有信号处

我有一个家庭作业,我应该写一个C程序来生成一个孩子。父级打开一个文件,并通过读取每一行、打印行号和行内容,然后倒带文件来永久循环

子进程以随机间隔向父进程发送SIGUSR1信号。为了创造这些间歇时间,我选择让孩子睡觉

当收到第一个信号时,父级跳过打印语句。当接收到另一个SIGUSR1信号时,它再次开始打印。它一直持续到随机数目的信号被发送为止。然后它忽略了五个信号。忽略五个信号后,父进程打印接收到的信号数,并在接收到一个以上的信号后退出

我的问题是,当信号从子进程发送时,程序崩溃。父进程有信号处理程序,但从未使用过。我犯了什么错误

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

void checkArguments(int nbrOfArg);
static void sig_exit(int signo);
static void sig_handler(int signo);

int sigcount, n;

int main(int argc, char *argv[]){
    int interval, i, linecount = 1;
    char buffer[1024];
    FILE *f;
    sigcount = 0;
    signal(SIGUSR1, sig_handler);
    srand(time(NULL)); // generate random numbers   
    n = rand() % 20 + 10;
    if(fork() != 0){ //parent process
        printf("%d\n", getpid()); //debugging
        checkArguments(argc);
        f = fopen(argv[1], "r"); //open file
        if(f == NULL){
            printf("Error opening file\n");
            exit(EXIT_FAILURE);
        }
        if(sigcount < n){ //n is random number of signals sent that starts/stops printing
            signal(SIGUSR1, sig_handler); //set signal handler
            do {
                while(!feof(f)){// infinite printing loop
                    fgets(buffer, 1024, f);
                    if(sigcount % 2 == 0){ //stop printing at odd number of signals received
                        printf("%d %s", linecount, buffer);
                    }   
                    linecount++;
                }
                rewind(f);
                linecount = 1;  
            } while(linecount == 1); //infinite loop
        } else if(sigcount < (n + 6)) {
            signal(SIGUSR1, SIG_IGN);   // ignore signal
        } else {
            printf("%d signals received", sigcount);
            signal(SIGUSR1, sig_exit); // terminate parent process
        }   
    } else {
        for(i = 0; i < n; i++){
            interval = rand() % 10 + 1; //send signals at random interval
            sigcount++; //number of signals sent
            printf("Sending signal %d from %d to %d\n", sigcount, getpid(), getppid()); //debugging
            kill(getppid(), SIGUSR1); //send signal
            printf("Child sleeping for %d seconds\n", interval); //debugging
            sleep(interval); //let child sleep after sending signal
        }
    }
}

/** Checks so command line argument is valid **/
void checkArguments(int nbrOfArg){
    int k;
    if(nbrOfArg != 2){
        printf("Wrong number of arguments");
        exit(-1);
    }
}

void sig_handler(int signo){
    if(signo == SIGUSR1){
        printf("Receivied SIGUSR1 signal\n");   
    } else printf("Error: received undefined signal\n");

}

void sig_exit(int signo){
    if(signo == SIGUSR1){
        printf("Received SIGUSR1 signal\n");
        exit(SIGUSR1);  
    } else printf("Error: received undefined signal\n");
}
#包括
#包括
#包括
#包括
#包括
无效校验参数(int-nbrOfArg);
静态无效信号出口(int signo);
静态无效信号处理器(int signo);
int-sigcount,n;
int main(int argc,char*argv[]){
整数间隔,i,行数=1;
字符缓冲区[1024];
文件*f;
sigcount=0;
信号(SIGUSR1,sig_处理器);
srand(time(NULL));//生成随机数
n=rand()%20+10;
如果(fork()!=0){//父进程
printf(“%d\n”,getpid());//调试
校验参数(argc);
f=fopen(argv[1],“r”);//打开文件
如果(f==NULL){
printf(“打开文件时出错”);
退出(退出失败);
}
if(sigcount
除了在注释中提出的要点之外,您还应该查看信号处理程序的设置位置,这是在您调用fork()并启动子进程之后,因此您得到的是父进程和子进程之间的竞争条件:

         fork()
      /         \
 Parent          Child
 CheckArguments  Send signal     
 Open file
 Create Handler
因此,在父级注册其处理程序之前,子级启动并发送一个信号。您可以通过在孩子发送第一个信号之前在孩子中添加睡眠来检查这是否是问题

信号的行为在Unix的不同版本之间也有所不同,当我在我的机器上尝试您的代码时,第一个信号被捕获,但之后就没有了。这是因为在我的机器上,信号处理程序在运行后被卸载,您需要将其作为信号处理程序的一部分重新启用

void sig_handler(int signo){
    if(signo == SIGUSR1)
    {
        printf("Receivied SIGUSR1 signal\n");
    } 
    else {
        printf("Error: received undefined signal\n");
    }
    signal(SIGUSR1, sig_handler);
}

我也会考虑使用SIGACT(而不是SigalAudio),它可以更好地控制信号处理。

< P>除了注释中所指出的点之外,还应该查看设置信号处理程序的位置,这是在调用Frk()之后。然后启动子进程,这样您就有了父进程和子进程之间的竞争条件:

         fork()
      /         \
 Parent          Child
 CheckArguments  Send signal     
 Open file
 Create Handler
因此,在父级注册其处理程序之前,子级启动并发送一个信号。您可以通过在子级发送第一个信号之前添加睡眠来检查是否存在此问题

信号的行为在Unix的不同版本之间也有所不同,当我在我的机器上尝试您的代码时,第一个信号被捕获,但之后就没有了。这是因为在我的机器上,信号处理程序在运行后被卸载,您需要将其作为信号处理程序的一部分重新启用

void sig_handler(int signo){
    if(signo == SIGUSR1)
    {
        printf("Receivied SIGUSR1 signal\n");
    } 
    else {
        printf("Error: received undefined signal\n");
    }
    signal(SIGUSR1, sig_handler);
}

我也会考虑使用SIGACT(而不是SigalAudio),它可以更好地控制信号处理。

< P>不同的系统使用<代码>信号()/代码>有不同的行为。在MAC运行的MaOS(101.1MjavaE,但它也适用于其他版本),原始代码使用<代码>信号()。工作正常-有各种各样的陷阱,但信号处理工作正常。在运行Ubuntu18.04 LTS(托管在同一Mac上)的VM中,使用
signal()
的代码工作不正常,因为,当信号被捕获时,在输入信号处理程序之前,信号处理将重置为默认值。这设置了竞争条件。这两种不同的行为都符合标准C-macOS提供“可靠的信号”,而Linux不提供

然而,并没有失去一切;Linux和macOS都有一个
$ ./sig41 sig41.c
3247
1 #define _XOPEN_SOURCE 700
Sending signal 1 of 30 from 3248 to 3247
Child sleeping for 7 seconds
Received SIGUSR1 signal 1 of 15
Sending signal 2 of 30 from 3248 to 3247
Child sleeping for 7 seconds
Received SIGUSR1 signal 2 of 15
30     sa.sa_flags = 0;
31     sigemptyset(&sa.sa_mask);
…
56                     }
57                     linecount++;
Sending signal 3 of 30 from 3248 to 3247
Child sleeping for 1 seconds
Received SIGUSR1 signal 3 of 15
Sending signal 4 of 30 from 3248 to 3247
Child sleeping for 4 seconds
Received SIGUSR1 signal 4 of 15
62                 rewind(f);
63                 linecount = 1;
…
76             sigaction(SIGUSR1, &sa, 0);
77         }
Sending signal 5 of 30 from 3248 to 3247
Child sleeping for 2 seconds
Received SIGUSR1 signal 5 of 15
Sending signal 6 of 30 from 3248 to 3247
Child sleeping for 3 seconds
Received SIGUSR1 signal 6 of 15
86         {
87             int interval = rand() % 10 + 1;
…
96         }
97     }
Sending signal 7 of 30 from 3248 to 3247
Child sleeping for 7 seconds
Received SIGUSR1 signal 7 of 15
Sending signal 8 of 30 from 3248 to 3247
Child sleeping for 10 seconds
Received SIGUSR1 signal 8 of 15
8 static void sig_exit(int signo);
9 static void sig_handler(int signo);
…
46         {
47             int linecount = 1;
Sending signal 9 of 30 from 3248 to 3247
Child sleeping for 5 seconds
Received SIGUSR1 signal 9 of 15
Sending signal 10 of 30 from 3248 to 3247
Child sleeping for 8 seconds
Received SIGUSR1 signal 10 of 15
68             printf("Going into SIG_IGN mode\n");
69             sa.sa_handler = SIG_IGN;
…
98 }
99 
Sending signal 11 of 30 from 3248 to 3247
Child sleeping for 9 seconds
Received SIGUSR1 signal 11 of 15
Sending signal 12 of 30 from 3248 to 3247
Child sleeping for 4 seconds
Received SIGUSR1 signal 12 of 15
18         exit(EXIT_FAILURE);
19     }
…
32     sigaction(SIGUSR1, &sa, 0);
33 
Sending signal 13 of 30 from 3248 to 3247
Child sleeping for 6 seconds
Received SIGUSR1 signal 13 of 15
Sending signal 14 of 30 from 3248 to 3247
Child sleeping for 6 seconds
Received SIGUSR1 signal 14 of 15
58                     // nap time = quarter second
59                     struct timespec nap = { .tv_sec = 0, .tv_nsec = 250000000 };
…
80     {
81         fclose(f);
Sending signal 15 of 30 from 3248 to 3247
Child sleeping for 7 seconds
Received SIGUSR1 signal 15 of 15
Sending signal 16 of 30 from 3248 to 3247
Child sleeping for 8 seconds
Received SIGUSR1 signal 16 of 15
110 {
111     if (signo == SIGUSR1)
…
22     if (f == NULL)
23     {
Sending signal 17 of 30 from 3248 to 3247
Child sleeping for 1 seconds
Received SIGUSR1 signal 17 of 15
Sending signal 18 of 30 from 3248 to 3247
Child sleeping for 6 seconds
Received SIGUSR1 signal 18 of 15
28     struct sigaction sa = { 0 };
29     sa.sa_handler = sig_handler;
…
^C
$