当前位置: 首页 > news >正文

Linux信号sigaction / signal

Linux信号sigaction / signal

文章目录

  • Linux信号sigaction / signal
    • 目的
    • 函数原型
    • struct sigaction
    • 信号枚举值
      • ISO C99 signals.
      • Historical signals specified by POSIX.
      • New(er) POSIX signals (1003.1-2008, 1003.1-2013).
      • Nonstandard signals found in all modern POSIX systems(including both BSD and Linux).
    • 测试
      • 1 处理信号后重启系统调用
      • 2 处理信号后不重启系统调用
      • 3 使用 sigaction 函数为 SIGUSR1 和 SIGUSR2 信号注册处理函数
    • 实际代码框架
      • 1. signal
      • 2 将程序放入线程中
    • 终端间通过kill发送信号
    • Reference

目的

我们可以通过sigaction函数或者signal指定某种特定信号,在程序执行过程中,通过发送信号,达到改变程序运行状态的目的,比如让程序停止等。

函数原型

获取或者设定与指定信号相关联的处理动作。

/* Get and/or set the action for signal SIG.  */
extern int sigaction (int __sig, const struct sigaction *__restrict __act,struct sigaction *__restrict __oact) __THROW;extern __sighandler_t signal (int __sig, __sighandler_t __handler)__THROW;

sigaction函数执行信号处理程序时,会把当前信号加入到进程的信号屏蔽字中,从而防止在进行信号处理期间信号丢失。

程序接收信号示意图

对signal(),Linux默认会自动重启动被中断的系统调用;

而对于 sigaction(),Linux默认并不会自动重启动,所以如果希望执行信号处理后自动重启动先前中断的系统调用,就需要为sa_flags指定 SA_RESTART标志

struct sigaction

当信号到达时,用于描述采取的动作的结构

/* Structure describing the action to be taken when a signal arrives.  */
struct sigaction{/* Signal handler.  */
#if defined __USE_POSIX199309 || defined __USE_XOPEN_EXTENDEDunion{/* Used if SA_SIGINFO is not set.  */__sighandler_t sa_handler;/* Used if SA_SIGINFO is set.  */void (*sa_sigaction) (int, siginfo_t *, void *);}__sigaction_handler;
# define sa_handler	__sigaction_handler.sa_handler
# define sa_sigaction	__sigaction_handler.sa_sigaction
#else__sighandler_t sa_handler;
#endif/* Additional set of signals to be blocked.  */__sigset_t sa_mask;/* Special flags.  */int sa_flags;/* Restore handler.  */void (*sa_restorer) (void);};
  • sa_handler 和signal()的参数__handler相同,代表新的信号处理函数
  • sa_mask 表示处理信号时,需要阻止的信号集
  • sa_flags 处理信号时的标志位
    • SA_RESETHAND:在调用处理函数前,将信号的处理函数重置为缺省值(即SIG_IGN)
    • SA_RESTART:执行信号处理后,自动重启先前中断的系统调用
    • SA_NODEFER :一般情况下, 当信号处理函数运行时,内核将阻塞该给定信号。但是如果设置了 SA_NODEFER标记, 那么在该信号处理函数运行时,内核将不会阻塞该信号
    • SA_ONSTACK:使用由sigaltstack()安装的备选栈
    • SA_SIGINFO:调用信号处理程序时携带了额外参数(提供了关于信号的深入信息)

信号枚举值

ISO C99 signals.

符号数值含义
SIGINT2Interactive attention signal.
SIGILL4Illegal instruction.
SIGABRT6Abnormal termination.
SIGFPE8Erroneous arithmetic operation.
SIGSEGV11Invalid access to storage.
SIGTERM15Termination request.

Historical signals specified by POSIX.

符号数值含义
SIGHUP1Hangup.
SIGQUIT3Quit.
SIGTRAP5Trace/breakpoint trap.
SIGKILL9Killed.
SIGBUS10Bus error.
SIGSYS12Bad system call.
SIGPIPE13Broken pipe.
SIGALRM14Alarm clock.

New(er) POSIX signals (1003.1-2008, 1003.1-2013).

符号数值含义
SIGURG16Urgent data is available at a socket.
SIGSTOP17Stop, unblockable.
SIGTSTP18Keyboard stop.
SIGCONT19Continue.
SIGCHLD20Child terminated or stopped.
SIGTTIN21Background read from control terminal.
SIGTTOU22Background write to control terminal.
SIGPOLL23Pollable event occurred (System V).
SIGXCPU24CPU time limit exceeded.
SIGXFSZ25File size limit exceeded.
SIGVTALRM26Virtual timer expired.
SIGPROF27Profiling timer expired.
SIGUSR130User-defined signal 1.
SIGUSR231User-defined signal 2.

Nonstandard signals found in all modern POSIX systems(including both BSD and Linux).

符号数值含义
SIGWINCH28Window size change (4.3 BSD, Sun).

测试

1 处理信号后重启系统调用

#include <iostream>
#include "stdio.h"
#include <signal.h>
#include <stdlib.h>void signalHandle(int signum) {if(signum  = SIGINT) {std::cout << "SIGINT recived" << std::endl;}
}int main(void){struct sigaction act;sigemptyset(&act.sa_mask);//这里使用SA_RESTART执行信号处理后自动重启到先前中断的系统调用,可以多次捕捉信号act.sa_flags = (SA_SIGINFO|SA_RESTART);act.sa_handler = signalHandle;sigaction(SIGINT, &act, NULL);while(1){}
}

当按下 CTRL + c时,会一直打印。

$ ./main 
^CSIGINT recived
^CSIGINT recived
^CSIGINT recived

2 处理信号后不重启系统调用

#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>void show_handler(int sig)
{printf("I got signal %dn\n", sig);int i;for(i = 0; i < 5; i++) {printf("i = %dn\n", i);sleep(1);}
}int main(void)
{// section 1int i = 0;struct sigaction act, oldact;act.sa_handler = show_handler;sigaddset(&act.sa_mask, SIGQUIT);         act.sa_flags = SA_RESETHAND | SA_NODEFER; //act.sa_flags = 0;                       sigaction(SIGINT, &act, &oldact);while(1) {sleep(1);printf("sleeping %dn\n", i);i++;}return 0;
}

程序起来后,控制台输入CTRL + c,能够接收到信号。再次输入时,程序退出。

(base) qiancj@qiancj-Dell-G15-5510:~/codes/test/build$ ./main 
sleeping 0
sleeping 1
^CI got signal 2
i = 0
i = 1
i = 2
i = 3
i = 4
sleeping 2
^C
(base) qiancj@qiancj-Dell-G15-5510:~/codes/test/build$ 

3 使用 sigaction 函数为 SIGUSR1 和 SIGUSR2 信号注册处理函数

#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>static void sig_usr(int signum)
{if(signum == SIGUSR1){printf("SIGUSR1 received\n");}else if(signum == SIGUSR2){printf("SIGUSR2 received\n");}else{printf("signal %d received\n", signum);}
}int main(void)
{
// section 2char buf[512];int  n;struct sigaction sa_usr;sa_usr.sa_flags = 0;sa_usr.sa_handler = sig_usr;   //信号处理函数sigaction(SIGUSR1, &sa_usr, NULL);sigaction(SIGUSR2, &sa_usr, NULL);printf("My PID is %dn\n", getpid());while(1){if((n = read(STDIN_FILENO, buf, 511)) == -1){if(errno == EINTR){printf("read is interrupted by signal\n");}}else{buf[n] = '0';printf("%d bytes read: %s\n", n, buf);}}return 0;
}

当一个终端启动程序,获取当前PID号(13770),另一个终端输入kill -USR1 32230或者kill -USR2 32230,第一个终端就会收到中断信号

(base) qiancj@qiancj-Dell-G15-5510:~/codes/test/build$ ./main
My PID is 32230nSIGUSR1 received
read is interrupted by signal
SIGUSR2 received
read is interrupted by signal

实际代码框架

当程序需要一直运行时,需要人为中断停止时,可以使用信号函数,具体框架可以设置为以下2种:

1. signal

#include <csignal>
#include <iostream>
#include <sstream>
#include <string>
#include <thread>sig_atomic_t stop_flag = 0;void INTSigHandler(int32_t num) {stop_flag = 1;std::cout << "  Signal Interactive attention " << num << " received."<< std::endl;
}int main(int argc, char **argv) {signal(SIGINT, INTSigHandler);// work always.......while ((!stop_flag)) {LOG_INFO << "I am working...";std::this_thread::sleep_for(std::chrono::seconds(1));}// Stop working! Go to rest!return 0;
}

2 将程序放入线程中

#include <chrono>
#include <csignal>
#include <cstdint>
#include <cstdio>
#include <cstdlib>namespace {std::atomic_bool continueExecution{true};void SigTermHandler(int signal) {if (signal == SIGTERM || signal == SIGINT) {// set atomic exit flagcontinueExecution = false;}
}bool RegisterSigTermHandler() {struct sigaction sa;sa.sa_handler = SigTermHandler;sa.sa_flags = 0;sigemptyset(&sa.sa_mask);// register signal handlerif (sigaction(SIGTERM, &sa, NULL) == -1) {// Could not register a SIGTERM signal handlerreturn false;}if (sigaction(SIGINT, &sa, NULL) == -1) {// Could not register a SIGTERM signal handlerreturn false;}return true;
}}  // namespacevoid ThreadAct1();void ThreadAct1() {while (continueExecution) {// always work......// sleepstd::this_thread::sleep_for(std::chrono::milliseconds(10000));}
}int main(int argc, char *argv[]) {if (!RegisterSigTermHandler()) {std::cout << "Unable to register signal handler" << std::endl;}// start threadstd::thread act1(ThreadAct1);act1.join();return 0;
}

终端间通过kill发送信号

(base) qiancj@qiancj-Dell-G15-5510:~$ kill --help
kill: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]Send a signal to a job.Send the processes identified by PID or JOBSPEC the signal named bySIGSPEC or SIGNUM.  If neither SIGSPEC nor SIGNUM is present, thenSIGTERM is assumed.Options:-s sig	SIG is a signal name-n sig	SIG is a signal number-l	list the signal names; if arguments follow `-l' they areassumed to be signal numbers for which names should be listed-L	synonym for -lKill is a shell builtin for two reasons: it allows job IDs to be usedinstead of process IDs, and allows processes to be killed if the limiton processes that you can create is reached.Exit Status:Returns success unless an invalid option is given or an error occurs.

信号种类

(base) qiancj@qiancj-Dell-G15-5510:~$ kill -l1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	

Reference

  • linux中sigaction函数详解
  • sigaction详细解析
http://www.lryc.cn/news/58974.html

相关文章:

  • 坦克大战第一阶段代码
  • 博客系统前端实现
  • ChatGPT技术原理、研究框架,应用实践及发展趋势(附166份报告)
  • 【屏幕自适应页面适配问题】CSS的@media,为了适应1440×900的屏幕,使用@media解决问题
  • 一篇文章理解堆栈溢出
  • 优化模型验证关键代码27:多旅行商问题的变体-多起点单目的地问题和多汉密尔顿路径问题
  • 快速搭建第一个SpringCloud程序
  • 【离散数学】图论
  • 代码随想录算法训练营第三十七天-贪心算法6| 738.单调递增的数字 968.监控二叉树 总结
  • 【Linux】线程中的互斥锁、条件变量、信号量(数据安全问题、生产消费模型、阻塞队列和环形队列的实现)
  • MySQL8.0的安装和配置
  • LinuxGUI自动化测试框架搭建(三)-虚拟机安装(Hyper-V或者VMWare)
  • 改进YOLO系列:数据增强扩充(有增强图像和标注),包含copypaste、翻转、cutout等八种增强方式
  • c++11 标准模板(STL)(std::stack)(一)
  • C++-c语言词法分析器
  • Maven工具复习
  • 算法总结-深度优先遍历和广度优先遍历
  • 【Linux】Centos安装mvn命令(maven)
  • 驱动保护 -- 通过PID保护指定进程
  • spring常用注解(全)
  • Axios请求(对于ajax的二次封装)——Axios请求的响应结构、默认配置
  • (三)【软件设计师】计算机系统—CPU习题联系
  • win下配置pytorch3d
  • JS字符串对象
  • Linux系统对文件及目录的权限管理(chmod、chown)
  • 半透明反向代理 (基于策略路由)
  • 课前测5-超级密码
  • QML控件--Menu
  • 002:Mapbox GL更改大气、空间及星星状态
  • 2022年第十三届蓝桥杯题解(全)C/C++