我是Linux的新手,我还在学习我的代码工作很简单,它从父母那里收到一个信号,孩子必须忽略这个信号,并打印信号的编号,比如1,3,4,9,11,但我的问题是,孩子在信号后面没有打印任何东西,我想让孩子忽略这些信号,特别是signals。这是我的代码。
// C program to implement sighup(), sigint()
// and sigquit() signal functions
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
// function declaration
void sighup();
void sigint();
void sigquit();
void sigsegv();
// driver code
void main()
{
int pid;
/* get child process */
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0) { /* child */
signal(SIGHUP, sighup);
signal(SIGINT, sigint);
signal(SIGQUIT, sigquit);
signal(SIGSEGV, sigsegv);
for (;;)
; /* loop for ever */
}
else /* parent */
{ /* pid hold id of child */
printf("\nPARENT: sending SIGHUP\n\n");
kill(pid, SIGHUP);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGINT\n\n");
kill(pid, SIGINT);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGQUIT\n\n");
kill(pid, SIGQUIT);
sleep(3);
}
}
// sighup() function definition
void sighup()
{
signal(SIGHUP, sighup); /* reset signal */
printf("CHILD: 1 [sighub]\n");
}
// sigint() function definition
void sigint()
{
signal(SIGINT, sigint); /* reset signal */
printf("CHILD: 2 [sigint]\n");
}
// sigsegv() function definition
void sigsegv()
{
signal(SIGSEGV, sigsegv); /* reset signal */
printf("CHILD: 11 [sigsegv]\n");
}
// sigquit() function definition
void sigquit()
{
signal(SIGINT, sigquit); /* reset signal */
printf("3 [sigquit]\n");
}发布于 2021-11-10 12:08:19
检查/usr/bin/include中的signal.h,信号处理程序
/* Type of a signal handler. */
typedef void (*__sighandler_t) (int);因此,需要同时更改转发声明和函数定义,以匹配此原型
// C program to implement sighup(), sigint()
// and sigquit() signal functions
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
// function declaration
void sighup(int);
void sigint(int);
void sigquit(int );
void sigsegv(int );
// driver code
int main()
{
int pid;
/* get child process */
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0) { /* child */
signal(SIGHUP, sighup);
signal(SIGINT, sigint);
signal(SIGQUIT, sigquit);
signal(SIGSEGV, sigsegv);
for (;;)
; /* loop for ever */
}
else /* parent */
{ /* pid hold id of child */
printf("\nPARENT: sending SIGHUP\n\n");
kill(pid, SIGHUP);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGINT\n\n");
kill(pid, SIGINT);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGQUIT\n\n");
kill(pid, SIGQUIT);
sleep(3);
}
return 0 ;
}
// sighup() function definition
void sighup(int signo)
{
signal(SIGHUP, sighup); /* reset signal */
printf("CHILD: 1 [sighub]\n");
}
// sigint() function definition
void sigint(int signo)
{
signal(SIGINT, sigint); /* reset signal */
printf("CHILD: 2 [sigint]\n");
}
// sigsegv() function definition
void sigsegv(int signo)
{
signal(SIGSEGV, sigsegv); /* reset signal */
printf("CHILD: 11 [sigsegv]\n");
}
// sigquit() function definition
void sigquit(int signo)
{
signal(SIGINT, sigquit); /* reset signal */
printf("3 [sigquit]\n");
}发布于 2021-11-10 22:21:24
正如评论中提到的,像printf()这样的stdio函数在信号处理程序中使用是不安全的。在Linux上,您还应该使用sigaction()而不是signal()来安装信号处理程序,因为这避免了后面的函数中处理程序如何工作的不精确定义的一些问题(应该只在面向基本的标准C而不是POSIX时使用,因为在POSIX中,信号处理程序可以做的事情比POSIX更受限制)。
然而,当以Linux或Unix平台为目标时,您根本不需要信号处理程序来完成此任务!每个进程都有一个信号掩码,该掩码控制阻止哪些信号正常执行处理程序或关闭默认操作。如果进程阻塞信号X接收到该信号,则认为该信号处于挂起状态,还有其他方法可以接收该信号。在Linux中,一种这样的方法是使用signalfd,这是一种特殊的文件描述符,可以从中读取以获取有关挂起信号的信息。一个使用它的例子:
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/signalfd.h>
#include <sys/types.h>
#include <sys/wait.h>
int child_main(const sigset_t *, int);
void send_signals(pid_t, int *);
int main(void) {
// The signals we want to catch
int signals[] = {SIGHUP, SIGINT, SIGQUIT, SIGSEGV, -1};
// Set up the signal mask
sigset_t sigs, oldmask;
sigemptyset(&sigs);
for (int i = 0; signals[i] >= 0; i++) {
sigaddset(&sigs, signals[i]);
}
// To avoid a race condition where the parent starts sending signals
// before the child is ready for them, block the signals before
// forking the child
if (sigprocmask(SIG_BLOCK, &sigs, &oldmask) < 0) {
perror("sigprocmask");
return EXIT_FAILURE;
}
pid_t child = fork();
if (child < 0) {
perror("fork");
return EXIT_FAILURE;
} else if (child == 0) {
// In the child process
return child_main(&sigs, (sizeof signals / sizeof signals[0]) - 1);
} else {
// Parent process. Restore the original signal mask and send child signals
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
perror("parent sigprocmask");
kill(child, SIGKILL);
return EXIT_FAILURE;
}
send_signals(child, signals);
// Wait for the child to finish
if (waitpid(child, NULL, 0) < 0) {
perror("parent waitpid");
return EXIT_FAILURE;
}
}
return 0;
}
void send_signals(pid_t proc, int *signals) {
for (int i = 0; signals[i] >= 0; i++) {
printf("Sending process %d signal %s (%d)\n", (int)proc,
strsignal(signals[i]), signals[i]);
if (kill(proc, signals[i]) < 0) {
printf("Failed: %s\n", strerror(errno));
}
}
}
int child_main(const sigset_t *sigs, int nsigs) {
// Create a signalfd that monitors the given signals
int fd = signalfd(-1, sigs, 0);
if (fd < 0) {
perror("child signalfd");
return EXIT_FAILURE;
}
struct signalfd_siginfo s;
// Loop up to nsigs times reading from the signal fd
int count = 0;
while (++count <= nsigs && read(fd, &s, sizeof s) == sizeof s) {
printf("Child received signal %s (%d)\n", strsignal(s.ssi_signo),
s.ssi_signo);
}
if (count <= nsigs && errno != EINTR) {
perror("child read");
close(fd);
return EXIT_FAILURE;
}
close(fd);
return 0;
}输出示例:
Sending process 17248 signal Hangup (1)
Sending process 17248 signal Interrupt (2)
Sending process 17248 signal Quit (3)
Sending process 17248 signal Segmentation fault (11)
Child received signal Hangup (1)
Child received signal Segmentation fault (11)
Child received signal Interrupt (2)
Child received signal Quit (3)发布于 2021-11-11 11:01:44
你的程序在我的机器上运行得很好,所以我不明白为什么你说孩子不打印任何东西。
无论如何,你必须小心,因为孩子正在打印接收到的信号的消息,但永远运行,这意味着当父母完成并exit()s时,你让孩子运行……永远?(并且您在没有停止或阻塞的情况下运行该子进程,因此消耗了所有可用的cpu)
您必须设计一种方法来杀死这样一个进程,因为如果您不这样做,您将以代表您运行的许多进程结束,除了忽略您对它们所做的kill()之外,什么也不做。
因此,有一些信号是不可忽略的,SIGKILL就是其中之一,出于安全原因,您不能为其安装信号处理程序……:)
此外,当使用signal(2)系统调用时,处理程序在接收到第一个信号时执行,并在信号处理程序完成时切换到默认行为(取决于信号)。
如果您希望它是永久的,您需要重新安装信号处理程序(这有一个竞争条件,以防您在执行信号处理程序时接收到第二个信号,但没有时间再次安装它),或者调用sigaction(2),这样您就可以永久地(在进程运行时,或者直到您对sigaction的下一次调用)安装一个不需要更新的信号处理程序。查看sigaction的手册页面,因为您需要学习如何使用它。
https://stackoverflow.com/questions/69910559
复制相似问题