如何使用 C 模拟 bash 中的信号(Ctrl+\ 和 Ctrl+C)?
How to simulate signals (Ctrl+\ and Ctrl+C) like in bash using C?
我想模拟信号 (Ctrl+\ and Ctrl+C) 在 bash 但使用 C.
我想使用信号函数终止子进程 void (*signal(int sig, void (*func)(int)))(int);
。
到目前为止我达到了:
#include <assert.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
pid_t cpid = 0;
void signal_handler(int sig) {
// char parent_str[] = "this is ctrl + c in the parent prosess\n";
char child_str[] = "this is ctrl + c in the child prosess\n";
// signal(sig, signal_handler);
if (sig == SIGINT) {
write(STDOUT_FILENO, child_str, sizeof(child_str) - 1);
kill(cpid, SIGINT);
}
else if (sig == SIGQUIT)
{
write(STDOUT_FILENO, "this is ctrl + \ in the child prosess\n", sizeof("this is ctrl + \ in the child prosess\n") - 1);
kill(cpid, SIGQUIT);
}
}
int main(int argc, char **argv) {
pid_t pid, pgid;
(void)argv;
signal(SIGINT, signal_handler);
signal(SIGQUIT, signal_handler);
pid = fork();
cpid = pid;
if (pid == 0) {
cpid = 1;
while(1);
exit(EXIT_SUCCESS);
}
wait (NULL);
printf("pid = %d\ncpisd = %d", pid, cpid);
while (1);
}
但是当我编译这段代码时,进程不会终止,为什么?
The process won't kill, why?
我认为令人困惑的部分是子进程也将使用与其父进程相同的 signal_handler
函数——即使 fork()
在 signal()
之后被调用。如果您希望子进程在收到来自父进程的信号时死亡,则处理程序应测试这是否是子进程(子进程的 cpid
设置为 1)并告诉它显式退出。
这是一个例子:
void signal_handler(int sig) {
// char parent_str[] = "this is ctrl + c in the parent prosess\n";
char child_str[] = "this is ctrl + c in the child prosess\n";
// signal(sig, signal_handler);
if (sig == SIGINT) {
write(STDOUT_FILENO, child_str, sizeof(child_str) - 1);
if(cpid != 1) {
kill(cpid, SIGINT);
} else {
exit(1);
}
}
else if (sig == SIGQUIT)
{
write(STDOUT_FILENO, "this is ctrl + \ in the child prosess\n", sizeof("this is ctrl + \ in the child prosess\n") - 1);
if(cpid != 1) {
kill(cpid, SIGQUIT);
} else {
exit(1);
}
}
}
当您 fork
a process almost everything that has occurred thus far is duplicated in the child process - that is to say, the child process has a nearly identical environment to its parent at the very moment fork
successfully returns. While there are some exceptions to this (as detailed in the man page for fork
) 信号处理程序被保留时。
当您键入 ^C 时,终端中发生的事情是 SIGINT
被发送到 both 您的 parent 和 child 进程。这是以相同的方式处理的,因为信号处理函数在 parent 和 child 中是相同的,但由于 cpid
.
的值而具有不同的结果
在parent中,cpid
是0
,因此kill
有这样的效果:
If pid equals 0, then sig is sent to every process in the process group of the calling process.
所以 parent 将信号“转发”给 child,因为它属于 parent 的进程组。
child进程因此接收到两个信号;一个直接来自终端,一个来自 parent 进程。使用相同的处理程序,但这次 cpid
是 1
,它调用 kill
并满足以下条件:
If pid is positive, then signal sig is sent to the process with the ID specified by pid.
所以这个调用
kill(1, SIGINT)
其中 PID 1 几乎肯定是 init,负责整个系统的根进程。这可能是件好事,但没有任何效果,否则您的系统可能会关闭。
最后,当每个进程沿着这条链推送信号时,什么都没有发生,但这就是我们看到三行文本的原因:一行来自 parent,两行来自 child .
我们希望在 parent 和 child 中以不同方式处理我们的信号,因此最好使用两个不同的处理程序。
由于从终端发送信号导致信号重叠,如果我们只想接受来自 [=75= 的信号,我们将必须确定是谁在 child ] 直接处理。 signal
handlers can not provide this level of detail, so instead we need sigaction
个处理程序。
这是一个小示例,它在 parent 和 child 之间拆分信号处理。在 child 中,我们使用 SA_SIGINFO
标志设置 struct sigaction
,这表明我们要使用 sa_sigaction
处理程序。我们使用 getppid
并将其与 info->si_pid
进行比较,以确定信号是否直接来自 parent。
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
static pid_t child_id;
void sigparent(int sig) {
const char msg[] = "The parent will kill the child.\n";
switch (sig) {
case SIGINT:
case SIGQUIT:
write(STDOUT_FILENO, msg, (sizeof msg) - 1);
kill(child_id, SIGQUIT);
break;
default:
break;
}
}
void sigchild(int sig, siginfo_t *info, void *ctx) {
const char msg[] = "The child will now die.\n";
if (getppid() == info->si_pid)
switch (sig) {
case SIGINT:
case SIGQUIT:
write(STDOUT_FILENO, msg, (sizeof msg) - 1);
_exit(EXIT_SUCCESS);
break;
default:
break;
}
}
void parent(void) {
signal(SIGINT, sigparent);
signal(SIGQUIT, sigparent);
puts("Parent will wait...");
waitpid(child_id, NULL, WUNTRACED);
puts("Parent is done waiting.");
}
void child(void) {
struct sigaction action = { 0 };
sigemptyset(&action.sa_mask);
action.sa_flags = (SA_SIGINFO);
action.sa_sigaction = sigchild;
sigaction(SIGINT, &action, NULL);
sigaction(SIGQUIT, &action, NULL);
while (1) {
puts("Child is sleeping...");
sleep(2);
}
}
int main(void) {
if ((child_id = fork()))
parent();
else
child();
}
我想模拟信号 (Ctrl+\ and Ctrl+C) 在 bash 但使用 C.
我想使用信号函数终止子进程 void (*signal(int sig, void (*func)(int)))(int);
。
到目前为止我达到了:
#include <assert.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
pid_t cpid = 0;
void signal_handler(int sig) {
// char parent_str[] = "this is ctrl + c in the parent prosess\n";
char child_str[] = "this is ctrl + c in the child prosess\n";
// signal(sig, signal_handler);
if (sig == SIGINT) {
write(STDOUT_FILENO, child_str, sizeof(child_str) - 1);
kill(cpid, SIGINT);
}
else if (sig == SIGQUIT)
{
write(STDOUT_FILENO, "this is ctrl + \ in the child prosess\n", sizeof("this is ctrl + \ in the child prosess\n") - 1);
kill(cpid, SIGQUIT);
}
}
int main(int argc, char **argv) {
pid_t pid, pgid;
(void)argv;
signal(SIGINT, signal_handler);
signal(SIGQUIT, signal_handler);
pid = fork();
cpid = pid;
if (pid == 0) {
cpid = 1;
while(1);
exit(EXIT_SUCCESS);
}
wait (NULL);
printf("pid = %d\ncpisd = %d", pid, cpid);
while (1);
}
但是当我编译这段代码时,进程不会终止,为什么?
The process won't kill, why?
我认为令人困惑的部分是子进程也将使用与其父进程相同的 signal_handler
函数——即使 fork()
在 signal()
之后被调用。如果您希望子进程在收到来自父进程的信号时死亡,则处理程序应测试这是否是子进程(子进程的 cpid
设置为 1)并告诉它显式退出。
这是一个例子:
void signal_handler(int sig) {
// char parent_str[] = "this is ctrl + c in the parent prosess\n";
char child_str[] = "this is ctrl + c in the child prosess\n";
// signal(sig, signal_handler);
if (sig == SIGINT) {
write(STDOUT_FILENO, child_str, sizeof(child_str) - 1);
if(cpid != 1) {
kill(cpid, SIGINT);
} else {
exit(1);
}
}
else if (sig == SIGQUIT)
{
write(STDOUT_FILENO, "this is ctrl + \ in the child prosess\n", sizeof("this is ctrl + \ in the child prosess\n") - 1);
if(cpid != 1) {
kill(cpid, SIGQUIT);
} else {
exit(1);
}
}
}
当您 fork
a process almost everything that has occurred thus far is duplicated in the child process - that is to say, the child process has a nearly identical environment to its parent at the very moment fork
successfully returns. While there are some exceptions to this (as detailed in the man page for fork
) 信号处理程序被保留时。
当您键入 ^C 时,终端中发生的事情是 SIGINT
被发送到 both 您的 parent 和 child 进程。这是以相同的方式处理的,因为信号处理函数在 parent 和 child 中是相同的,但由于 cpid
.
在parent中,cpid
是0
,因此kill
有这样的效果:
If pid equals 0, then sig is sent to every process in the process group of the calling process.
所以 parent 将信号“转发”给 child,因为它属于 parent 的进程组。
child进程因此接收到两个信号;一个直接来自终端,一个来自 parent 进程。使用相同的处理程序,但这次 cpid
是 1
,它调用 kill
并满足以下条件:
If pid is positive, then signal sig is sent to the process with the ID specified by pid.
所以这个调用
kill(1, SIGINT)
其中 PID 1 几乎肯定是 init,负责整个系统的根进程。这可能是件好事,但没有任何效果,否则您的系统可能会关闭。
最后,当每个进程沿着这条链推送信号时,什么都没有发生,但这就是我们看到三行文本的原因:一行来自 parent,两行来自 child .
我们希望在 parent 和 child 中以不同方式处理我们的信号,因此最好使用两个不同的处理程序。
由于从终端发送信号导致信号重叠,如果我们只想接受来自 [=75= 的信号,我们将必须确定是谁在 child ] 直接处理。 signal
handlers can not provide this level of detail, so instead we need sigaction
个处理程序。
这是一个小示例,它在 parent 和 child 之间拆分信号处理。在 child 中,我们使用 SA_SIGINFO
标志设置 struct sigaction
,这表明我们要使用 sa_sigaction
处理程序。我们使用 getppid
并将其与 info->si_pid
进行比较,以确定信号是否直接来自 parent。
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
static pid_t child_id;
void sigparent(int sig) {
const char msg[] = "The parent will kill the child.\n";
switch (sig) {
case SIGINT:
case SIGQUIT:
write(STDOUT_FILENO, msg, (sizeof msg) - 1);
kill(child_id, SIGQUIT);
break;
default:
break;
}
}
void sigchild(int sig, siginfo_t *info, void *ctx) {
const char msg[] = "The child will now die.\n";
if (getppid() == info->si_pid)
switch (sig) {
case SIGINT:
case SIGQUIT:
write(STDOUT_FILENO, msg, (sizeof msg) - 1);
_exit(EXIT_SUCCESS);
break;
default:
break;
}
}
void parent(void) {
signal(SIGINT, sigparent);
signal(SIGQUIT, sigparent);
puts("Parent will wait...");
waitpid(child_id, NULL, WUNTRACED);
puts("Parent is done waiting.");
}
void child(void) {
struct sigaction action = { 0 };
sigemptyset(&action.sa_mask);
action.sa_flags = (SA_SIGINFO);
action.sa_sigaction = sigchild;
sigaction(SIGINT, &action, NULL);
sigaction(SIGQUIT, &action, NULL);
while (1) {
puts("Child is sleeping...");
sleep(2);
}
}
int main(void) {
if ((child_id = fork()))
parent();
else
child();
}