你好,我在第二个程序中获得信号有问题。我有这样的代码:
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
的Instendtest
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%d 33[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
$ _