每当我的子进程结束时,我都试图调用一个函数。这是通过捕获execve()发送的sigchld来完成的。
我的问题是,我的处理函数并不总是第二次调用。有时候是这样,所以我有点困惑。
我的代码是这个:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h> // sigaction()
#include <time.h>
#include <errno.h>
#include <unistd.h>
#define MAX_LENGTH 1000
#define BILLION 1E9
struct timespec start,stop;
float totalTime = 0;
void runCommand(int signo)
{
printf("Run command called\n");
float processTime = 0;
//Get the time when the process ended
if(clock_gettime(CLOCK_MONOTONIC,&stop) == -1){
perror(NULL);
}
processTime = stop.tv_sec - start.tv_sec + ( stop.tv_nsec - start.tv_nsec ) / BILLION;
totalTime += processTime;
}
int main(int argc, char const *argv[]) {
int counter = 0;
int pid = 0;
int status;
char *args[4];
char line[MAX_LENGTH];
//Setup behaviour for SIGCHLD
struct sigaction psa;
psa.sa_handler = runCommand;
sigaction(SIGCHLD, &psa, NULL);
FILE *fp = fopen("script_file.txt","r");
if(!fp)
{
return 0;
}
//Setup argsgcc
args[0] = "/bin/sh";
args[1] = "-c";
args[3] = NULL;
while(fgets(line, MAX_LENGTH, fp))
{
printf("The command number %d is %s \n", counter, line);
//Get the time when the process started
if(clock_gettime(CLOCK_MONOTONIC,&start) == -1){
perror(NULL);
}
//Create a new process
pid = fork();
//Child process
if(pid == 0)
{
args[2] = line;
execve("/bin/sh", args, NULL);
}
//Parent process
else
{
wait(&status);
}
counter++;
}
printf("The overall time was %f seconds.\n", totalTime);
fclose(fp);
return 0;
}
当我试图运行它时,有时我的结果是:
The command number 0 is mkdir test/
Run command called
The command number 1 is sleep 0.5
Run command called
The command number 2 is sleep 1
Run command called
The command number 3 is rmdir test/
Run command called
The overall time was 1.544909 seconds.
看来是对的。
但在其他情况下,我的结果是:
The command number 0 is mkdir test/
Run command called
The command number 1 is sleep 0.5
The command number 2 is sleep 1
The command number 3 is rmdir test/
The overall time was 0.009810 seconds.
这让我相信sigaction并不总是接收到我的sigchld信号。
当我运行valgrind时,我得到以下错误:
==5407== All heap blocks were freed -- no leaks are possible
==5407==
==5407== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
==5407==
==5407== 1 errors in context 1 of 2:
==5407== Syscall param rt_sigaction(act->sa_flags) points to uninitialised byte(s)
==5407== at 0x4E6F5AE: __libc_sigaction (sigaction.c:62)
==5407== by 0x40098B: main (iv.c:40)
==5407== Address 0xffefff498 is on thread 1's stack
==5407== Uninitialised value was created by a stack allocation
==5407== at 0x400931: main (iv.c:29)
==5407==
==5407==
==5407== 1 errors in context 2 of 2:
==5407== Syscall param rt_sigaction(act->sa_mask) points to uninitialised byte(s)
==5407== at 0x4E6F5AE: __libc_sigaction (sigaction.c:62)
==5407== by 0x40098B: main (iv.c:40)
==5407== Address 0xffefff4a8 is on thread 1's stack
==5407== Uninitialised value was created by a stack allocation
==5407== at 0x400931: main (iv.c:29)
==5407==
==5407== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
但我不知道这意味着什么。
最佳答案
最简单的方法是初始化psa
为零初始化它:
struct sigaction psa = {0};
然而,也有微妙之处。不能从信号处理程序调用异步信号不安全函数,如
printf
。有关允许函数的列表,请参见signal safty
。您可以用printf
调用替换write(2)
,以避免:write(STDOUT_FILENO, "Run command called\n", sizeof "Run command called\n" - 1);
另外,在创建另一个子进程之前,您要对每个子进程执行
wait
。因此,任何时候都只有一个孩子在跑步。如果修改程序以允许多个子进程同时运行,并且子进程会在同一时间死掉,则无法捕获所有SIGCHLD
信号。例如,如果信号处理程序正在处理的sigchld是前一个sigchld,则它将丢失。因为挂起的信号将被丢弃,除非它们是不同的信号,除了实时信号。例如,如果SIGUSR1
在处理SIGCHLD
时到达(由信号处理程序处理),它将被阻止;但另一个SIGCHLD
将被忽略。关于c - 多次使用sigaction时出错,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49300920/