无法使用 execl()、、fork()、kill() 和信号检索信号

  • 本文关键字:信号 kill fork 检索 execl c
  • 更新时间 :
  • 英文 :


你好,我在第二个程序中获得信号有问题。我有这样的代码:

Program1:

int main() {
    int id = fork();
    
    if (id == 0) {
        execl("program2", "program2", NULL);
        kill(id, SIGUSR1);
    }
    return 0;
}

项目2:

void signal_handler1(int sig) {
    printf("testn");
}
int main(int argc, char* argv[]) {
    signal(SIGUSR1, signal_handler1);
    printf("Hello worldn");
    return 0;
}

为什么我得到

Hello World

的Instend
test
Hello World

execl()仅在发生错误时返回,因此如果execl()成功,kill()永远不会在program1中执行。它应该向父进程发送信号。但是信号可能在program2设置信号处理程序之前发送,因此信号可能被忽略。让它等待一段时间再发送信号:

#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
    pid_t id = fork();
    if (id == -1) {
        perror("fork");
        return 1;
    }
    if (id == 0)
    {   /* Child process */
        /* Execute program from current directory */
        execl("program2", "program2", NULL);
        perror("execl");
    } else
    {   /* Parent process */
        /* Wait while child setup signal handler */
        sleep(1);
        if (kill(id, SIGUSR1) == -1)
        {
            perror("kill");
        }
    }
    return 0;
}

如果你想让program2捕捉信号,让它等待信号:

#include <signal.h>
#include <unistd.h>
#include <stdio.h>
static sig_atomic_t sigusr1_received = 0;
static void signal_handler(int)
{
    sigusr1_received = 1;
}
int main(void)
{
    signal(SIGUSR1, signal_handler);
    printf("Hello World!n");
    while (1)
    {
        /* Check flag first to avoid race condition */
        if (sigusr1_received)
        {
            printf("testn");
            /* Exit after receiving signal */
            break;
        }
        pause();        /* Wait for any signal */
    }
    return 0;
}

查看父代码:

int main()
{
    int id = fork();
    
    if (id == 0) {
  • 你不测试负id(表明fork()的一些错误),但是,由于这个错误是罕见的,这不是一个问题在这里)
  • 你已经测试了id是否为零(就在上面),所以三思而后行,你是否杀死了进程id为0的进程?这个kill不应该在代码的其他部分吗?
  • execl()仅在确实失败时返回。你应该只打印一些关于为什么execl()失败和exit()的错误,并返回一个代码表明。
        execl("program2", "program2", NULL);
        fprintf(stderr, "EXECL: %sn", strerror(errno));
        exit(EXIT_FAILURE);
        /* kill(id, SIGUSR1); <-- this code will never execute */
    }
    return 0;
}

Exec函数永远不会返回,因为执行它们的程序被您试图执行的程序覆盖。所以,如果你调用execl(2),不要在它下面放任何东西,除了错误代码。它不像调用子程序那样,返回到调用程序。它永远不会返回(如前所述,只有当函数失败时才会返回)。

如果你想发送一个信号给你的孩子,kill()调用应该在if语句之后(实际上,是要执行的父代码)。你应该先检查-1,因为这意味着fork()失败了。

所以一个更好的示例代码将是:(我已经把,不像你所做的,一个完整的例子,准备在您的网站上建立和执行,请阅读如何创建一个最小的,可重复的例子,并遵循指导方针,在那里张贴可测试的代码。(你缺少头文件和许多东西来让这段代码可以开箱测试)

program1.c

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/time.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include "log.h"  /* see log.h file, below */
char *p1;
int   pid;
int main(int argc, char **argv)
{
    int res;
    p1       = argv[0];
    char *p2 = argc > 1 ? argv[1] : p1;
    pid      = getpid();
    LOG(p1, pid, "STARTINGn");
    LOG(p1, pid, "IGNORING SIGUSR1(%d)n", SIGUSR1);
    signal(SIGUSR1, SIG_IGN);
    int  id  = fork();
    if (id < 0) { /* error */
        ERR(p1, pid, "FORK: %sn", strerror(errno));
    }
    if (id == 0) { /* child process */
        pid  = getpid(); /* a new pid as we are children */
        if (argc <= 1) {
            ERR(p1, pid, "nothing to executen");
        }
        /* shift the parameters to get the next command name
         * and parameter list */
        argv++;
        argc--;
        LOG(p1, pid, "about to EXECV(");
        char *sep  = "";
        for (int i = 0; i < argc; i++) {
            LOG_TAIL("%s"%s"", sep, argv[i]);
            sep    = ", ";
        }
        LOG_TAIL(").n");
        /* we use execv(2) instead of execl(2) because
         * we are using the parameters as derived from
         * our own parameters, so we change (we did
         * above) the local parameters to main to get
         * the parameter list to execv(). */
        execv(p2, argv);
        ERR(p1, pid, "EXEC: %sn", strerror(errno));
    }
    /* id > 0 */
    LOG(p1, pid, "FORKed a new child (pid=%d)n", id);
    {   /* randomize, as all children start at the same time
         * calling srandom() with a time based value will not
         * be a good chance, so I selected to read the seed
         * value from /dev/random */
        static const char rand_dev[] = "/dev/random";
        int fd = open(rand_dev, O_RDONLY);
        int val;
        if (fd >= 0) {
            read(fd, &val, sizeof val);
            srandom(val);
            close(fd);
        } else {
            ERR(p1, pid, "%s: %sn", rand_dev, strerror(errno));
        }
    }
    int secs = random() % 10 + 1; /* 1..10 s. delay */
    LOG(p1, pid, "Waiting for %ds to next stepn", secs);
    sleep(secs); /* wait between 1 and 10s. */
    LOG(p1, pid, "Sending SIGUSR1(%d) to %s[pid=%d]n",
            SIGUSR1, p2, id);
    res = kill(id, SIGUSR1);
    if (res < 0) {
        LOG(p1, pid, "KILL(%d, SIGUSR1): %sn", id, strerror(errno));
    }
    LOG(p1, pid, "Waiting for %s[pid=%d] to finalizen", p2, id);
    int status;
    res = wait(&status); /* wait for child to end */
    if (res < 0) {
        /* error in wait(2) */
        ERR(p1, pid, "WAIT: %sn",
                strerror(errno));
    } else if (WIFEXITED(status)) {
        /* child called exit(2) */
        LOG(p1, pid, "WAIT: %s[pid=%d] terminated with exit code %d.n",
                p2, id, WEXITSTATUS(status));
    } else if (WIFSIGNALED(status)) {
        /* child was aborted by a signal */
        LOG(p1, pid, "WAIT: %s[pid=%d] terminated by signal %d%s.n",
                p2, id, WTERMSIG(status),
                WCOREDUMP(status)
                    ? ", and dumped a core file"
                    : "");
    }
    LOG(p1, pid, "finalizingn");
    exit(EXIT_SUCCESS);
} /* main */

program2.c

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "log.h"
char *pn;
int pid;
void signal_handler1(int sig) {
    LOG(pn, pid, "RECEIVED signal %dn", sig);
}
int main(int argc, char* argv[]) {
    pn = argv[0];
    pid = getpid();
    LOG(pn, pid, "STARTINGn");
    LOG(pn, pid, "Installing signal handler for SIGUSR1(%d)n",
            SIGUSR1);
    signal(SIGUSR1, signal_handler1);
    LOG(pn, pid, "Program params: ");
    char *sep = "";
    for (int i = 1; i < argc; i++) {
        LOG_TAIL("%s[%s]", sep, argv[i]);
        sep = ", ";
    }
    LOG_TAIL("n");
    if (argc > 1) { /* at least one parameter, so pause */
        LOG(pn, pid, "Waiting to receive a signaln");
        int res = pause();
        if (res < 0) {
            LOG(pn, pid, "PAUSE: %sn", strerror(errno));
        }
    }
    /* and print final message */
    LOG(pn, pid, "Hello world, program terminatingn");
    return 0;
}

两个程序都需要:

log.h

#ifndef _LOG_H
#define _LOG_H
#define F(_prog, _pid, _fmt) "%s:%s:%d:pid=33[1;%dm%d33[m:%s: "
    _fmt, _prog, __FILE__, __LINE__, (_pid % 7 + 31), (_pid), __func__
#define LOG_TAIL(_fmt, ...) 
        printf(_fmt, ##__VA_ARGS__)
#define LOG(_prog, _pid, _fmt, ...)     
        printf(F(_prog, _pid, " "_fmt), 
                ##__VA_ARGS__)
#define ERR(_prog, _pid, _fmt, ...) do {      
        printf(F(_prog, _pid, "ERROR: "_fmt), 
                ##__VA_ARGS__);               
        exit(EXIT_FAILURE);                   
    } while (0)
#endif /* _LOG_H */

,你可以用:

Makefile

targets = p1 p2
toclean = $(targets)
p1_objs = program1.o
p2_objs = program2.o
toclean += $(p1_objs) $(p2_objs)
all: $(targets)
clean:
    rm -f $(toclean)
p1: $(p1_objs)
    $(CC) $(CFLAGS) $(LDFLAGS) $($@_objs) -o $@
p2: $(p2_objs)
    $(CC) $(CFLAGS) $(LDFLAGS) $($@_objs) -o $@
program1.o program2.o: log.h

:

$ p1 p1 p2 
p1:program1.c:24:pid=11089:main:  STARTING
p1:program1.c:25:pid=11089:main:  IGNORING SIGUSR1(10)
p1:program1.c:62:pid=11089:main:  FORKed a new child (pid=11090)
p1:program1.c:83:pid=11089:main:  Waiting for 1s to next step
p1:program1.c:45:pid=11090:main:  about to EXECV("p1", "p2").
p1:program1.c:24:pid=11090:main:  STARTING
p1:program1.c:25:pid=11090:main:  IGNORING SIGUSR1(10)
p1:program1.c:62:pid=11090:main:  FORKed a new child (pid=11091)
p1:program1.c:83:pid=11090:main:  Waiting for 6s to next step
p1:program1.c:45:pid=11091:main:  about to EXECV("p2").
p2:program2.c:23:pid=11091:main:  STARTING
p2:program2.c:25:pid=11091:main:  Installing signal handler for SIGUSR1(10)
p2:program2.c:29:pid=11091:main:  Program params: 
p2:program2.c:46:pid=11091:main:  Hello world, program terminating
p1:program1.c:86:pid=11089:main:  Sending SIGUSR1(10) to p1[pid=11090]
p1:program1.c:92:pid=11089:main:  Waiting for p1[pid=11090] to finalize
p1:program1.c:86:pid=11090:main:  Sending SIGUSR1(10) to p2[pid=11091]
p1:program1.c:92:pid=11090:main:  Waiting for p2[pid=11091] to finalize
p1:program1.c:101:pid=11090:main:  WAIT: p2[pid=11091] terminated with exit code 0.
p1:program1.c:111:pid=11090:main:  finalizing
p1:program1.c:101:pid=11089:main:  WAIT: p1[pid=11090] terminated with exit code 0.
p1:program1.c:111:pid=11089:main:  finalizing
$ _

最新更新