wordpress 专栏页面,网站快速排名优化,wordpress feed地址,常用网站域名文章目录 1.什么是信号#xff1f;1.1信号是内容受限的一种异步通信机制1.2信号由谁发出的#xff1f;1.3信号由谁处理#xff0c;如何处理 2.常见的信号3.进程对信号的处理3.1用signal函数处理SIGINT信号3.2使用sigaction 函数 4.alarm 和pause函数4.1 alarm函数详解4.2 pa… 文章目录 1.什么是信号1.1信号是内容受限的一种异步通信机制1.2信号由谁发出的1.3信号由谁处理如何处理 2.常见的信号3.进程对信号的处理3.1用signal函数处理SIGINT信号3.2使用sigaction 函数 4.alarm 和pause函数4.1 alarm函数详解4.2 pause函数详解 1.什么是信号
1.1信号是内容受限的一种异步通信机制
在Linux中信号是一种进程间通信IPC的机制。它用于通知某个进程发生了某种事件或异常。信号的本质是一种软件层次的模拟硬件中断的方法。当某个事件发生时操作系统会向该事件的关联进程发送一个信号。进程接收到信号后可以选择忽略该信号或者执行相应的操作来响应该信号。 可以总结为以下三点 1信号的目的用来通信 2信号是异步的对比硬件中断 3信号的本质上是int型数字编号事先定义好的
1.2信号由谁发出的
信号可以由用户、系统或进程发送给目标进程。用户可以通过键盘输入、终端命令或系统调用等方式发送信号。系统则会在某些特定事件发生时自动发送信号例如进程终止、硬件异常等。进程也可以通过系统调用或信号发送函数来发送信号给其他进程。在Linux中可以使用kill命令或raise函数来向其他进程发送信号。某种软件条件满足后也会发出信号如alarm闹钟时间到会产生SIGALARM信号向一个读端已经关闭的管道write是会产生SIGPIPE信号。
1.3信号由谁处理如何处理
忽略信号进程可以选择忽略收到的信号。这是大多数程序对信号的处理方式。但是有些信号是不能被忽略的例如SIGKILL和SIGSTOP因为它们提供了使进程终止或停止的可靠方法。默认处理如果进程没有为某个信号设置自定义的处理函数那么系统会为该信号提供默认的处理方式。大多数信号的默认动作为终止进程。捕获信号进程可以注册一个信号处理函数来指定如何响应某个信号。当进程接收到该信号时会调用相应的处理函数来执行相应的操作。
2.常见的信号
1.SIGINT (2): 中断信号。通常由用户按下Ctrl C发送用于终止正在运行的程序。 2.SIGKILL (9): 杀死信号。这是一个无法被捕获或忽略的信号强制终止进程。 3.SIGTERM (15): 终止信号。通常用于请求进程正常终止。与SIGKILL不同进程可以捕获并且可以执行清理工作后再退出。 4.SIGSEGV (11): 段错误信号。当进程访问非法内存时触发通常表示有bug导致了内存访问错误。 5.SIGILL (4): 非法指令信号。当进程试图执行非法的CPU指令时触发。 6.SIGHUP (1): 挂起信号。通常在与终端的连接断开时发送给进程要求进程重新加载配置或重新初始化。 7.SIGUSR1 (10)和 SIGUSR2 (12): 用户自定义信号1和2。可以由用户自定义用途。 8.SIGALRM (14): 闹钟信号。通常由alarm()函数设置的定时器超时时发送给进程。
3.进程对信号的处理
3.1用signal函数处理SIGINT信号
当进程接收到SIGINT信号时可以注册一个signal函数来执行后台保存操作等。 捕获CtrlC 终止信号 代码演示
#include stdio.h
#include stdlib.h
#include signal.h
#include unistd.h void handle_signal(int signal_number) { printf(捕获到信号 %d\n, signal_number); printf(我要退出了);exit(0); // 退出程序
} int main() { // 注册SIGINT信号的处理函数为handle_signal signal(SIGINT, handle_signal); while (1) { printf(程序运行中... 正在等待信号\n); sleep(1); // 暂停1秒 } return 0;
}signal函数是用于注册信号处理程序的标准函数之一。有一些优点和缺点 优点
简单易用 signal函数是C标准库提供的使用起来相对简单能够快速地注册信号处理函数。基本功能完备 它提供了基本的信号处理功能允许你指定在接收到特定信号时应该执行的处理函数。
缺点无法简单地直接得知之前设置的对信号的处理方法。如果你使用 signal(SIGINT, new_handler) 来设置对 SIGINT 信号的新处理函数 new_handler那么你不能直接获取或查询在调用 signal 函数之前对 SIGINT 信号所设置的处理函数。这种情况下你无法在程序中简单地查询或检查当前 SIGINT 信号的处理函数是什么。这可能导致一定的不确定性特别是在多个模块设置信号处理函数或者需要了解之前的处理方式时。
3.2使用sigaction 函数
sigaction 是用于设置信号处理函数的高级函数相较于 signal 函数它提供了更多的控制和选项。通过 sigaction 函数可以更精确地管理信号处理。 sigaction 定义如下
#include signal.hstruct sigaction {void (*sa_handler)(int);void (*sa_sigaction)(int, siginfo_t *, void *);sigset_t sa_mask;int sa_flags;void (*sa_restorer)(void);
};int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);signum是信号的编号act是一个结构体 struct sigaction包含新的信号处理函数信号屏蔽集以及标志位oldact 是一个可选参数用于存储之前的信号处理配置信息。
struct sigaction 结构体包含以下字段
sa_handler指定处理信号的函数类似于 signal 函数中的处理函数。但与 signal 不同的是sa_handler 允许设置为 SIG_DFL默认操作或 SIG_IGN忽略信号。sa_sigaction可选项是带有更多信息的信号处理函数用于处理信号和附加信息。如果设置了这个函数sa_handler 就会被忽略。sa_mask用来设置在处理当前信号时需要屏蔽的信号集。sa_flags设置信号处理的一些标志位例如 SA_RESTART 表示在某些系统调用中自动重启。sa_restorer一些特定系统用到的字段一般无需设置。 sigaction 函数的返回值为 0 表示成功-1 表示失败。 使用sigaction函数代码演示
#include stdio.h
#include stdlib.h
#include signal.h
#include unistd.hvoid sigint_handler(int sig) {printf(捕获到 SIGINT 信号\n);printf(处理 SIGINT 信号...\n);exit(0);
}int main() {struct sigaction new_action, old_action;// 设置新的信号处理程序new_action.sa_handler sigint_handler;sigemptyset(new_action.sa_mask); // 清空信号屏蔽集new_action.sa_flags 0;// 设置SIGINT信号的新处理程序if (sigaction(SIGINT, new_action, old_action) -1) {perror(无法设置信号处理程序);return 1;}printf(按下 CtrlC 以发送 SIGINT 信号...\n);// 让程序保持运行等待信号while (1) {sleep(1);}return 0;
} 4.alarm 和pause函数
4.1 alarm函数详解
#include unistd.h
unsigned int alarm(unsigned int seconds);seconds 参数表示定时器的秒数。当定时器到达设定的秒数后会发送 SIGALRM 信号给当前进程。 注意返回值有点绕函数的返回值为前一个定时器剩余的秒数。如果之前有设置过定时器则返回之前定时器剩余的时间如果之前没有设置定时器则返回 0。 代码演示
#include stdio.h
#include unistd.h
#include signal.h
#include stdlib.h
#define DELAY 5
void alarm_handler(int signum) {printf(捕获到 SIGALRM 信号 bye\n);exit(0);
}int main() {signal(SIGALRM, alarm_handler); // 设置 SIGALRM 的处理函数unsigned int remaining_time alarm(DELAY); // 设置定时器为5秒printf(alarm 返回值为 %u \n, remaining_time); //这里的返回值其实为0 因为之前没有设置新的定时器只有一个的话返回为0printf(等待%ds\n,DELAY);while(1) {// 程序的其他工作可以在这里执行sleep(DELAY);}return 0;
}需要注意的是alarm 函数设置的定时器是单次定时器一旦定时器到时就会被取消。如果需要重复定时功能需要在 alarm_handler 函数中再次调用 alarm 来设置新的定时器。
4.2 pause函数详解
pause 函数是一个系统调用用于使调用进程挂起直到收到一个信号。它通常用于程序中暂时等待某个信号的到来。
int pause(void);pause 函数没有参数调用它会使当前进程挂起直到接收到一个信号为止。当进程接收到信号后如果信号的默认处理方式是终止进程那么进程将会终止。如果信号的默认处理方式是调用一个函数那么进程会执行相应的信号处理函数然后继续执行。通常pause 函数用于让进程等待某个信号的到来比如等待 SIGINT 或其他自定义信号。 代码演示
#include stdio.h
#include unistd.h
#include signal.h
#include stdlib.h
void sig_handler(int signum) {printf(捕获到自定义信号 %d\n, signum);if(signum10){printf(执行退出命令\n);exit(0) ;}if(signum12){printf(执行xxxx命令\n);}}int main() {signal(SIGUSR1, sig_handler); // 设置自定义信号的处理函数printf(等待自定义信号...\n);pause(); // 进程挂起等待自定义信号printf(自定义信号函数执行完毕程序退出\n);return 0;
}在终端编译运行之后新开一个终端。可以用kill 发送自定义信号发送给进程。例如
kill -s 12 5700其中12 为自定义信号Linux系统中一般10 或12 为自定义信号5700为进程的pid。 可以使用ps -aux 查看进程pid 效果如下