百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

Linux Signal 示例

toyiye 2024-06-21 12:26 8 浏览 0 评论

信号是系统响应某些条件而产生的一个事件,接收到该信的进程做出相应的处理。通常信是由错误产生的,如段错误(SIGSEGV)。 但信还可以作为进程间通信的一种方式,由一个进程发送给另一个进程。

信号定义在 signal.h 文件中,以 SIG 作为开头,可用 kill -l 命令查看,详细信息参见 man 7 signal

信号处理

信号可以通过 signal sigaction 函数来注册处理, signal 函数是 struct sigactionsa_handler 的一种便捷实现。

signal 函数

原型:

void (*signal(int sig, void (*func)(int)))(int);

其中 sig 是需要捕获的 signal number, 后一个是捕获到信号后的处理函数指针,所以处理函数的原型必须是 void func(int) ,简单的代码示例如下:

#include <stdio.h>
#include <string.h>
#include <signal.h>
static void
handler(int sig)
{
 printf("Recieved signal: %d\n", sig);
}
int
main(int argc, char *argv[])
{
 signal(SIGINT, handler);
 printf("Caught SIGINT, input 'quit' to exit...\n");
 // wait signal caught
 char buf[1024] = {0};
 while (1) {
 printf("Please input: ");
 scanf("%s", buf);
 if (strcmp(buf, "quit") == 0) {
 break;
 }
 }
 printf("Exit...\n");
 return 0;
}

另外 api 中也提供了下面 2 个特殊的 handler:

  • SIG_IGN

忽略此信号

  • SIG_DFL

恢复此信号的默认行为

sigaction 函数

原型:

int sigaction(int sig, const struct sigaction *restrict act,
 struct sigaction *restrict oact);

其中 sigsignal number, act 指定信号的处理行为, oact 如果不为 NULL 则返回信号之前的处理行为。

struct sigaction 的主要成员如下:

  • void(*) (int) sa_handler 处理函数指针,同 signal 函数中的 func 参数
  • sigset_t sa_mask 信号屏蔽字,是指当前被阻塞的一组信号,不能被当前进程收到
  • int sa_flags 处理行为修改器,指明哪种处理函数生效,详见下文
  • void(*) (int, siginfo_t *, void *) sa_sigaction 处理函数指针,仅 sa_flags == SA_SIGINFO 时有效 其中 sa_flags 主要可以设置为以下值:
  • SA_NOCLDSTOP

子进程停止时不产生 SIGCHLD 信号

  • SA_RESETHAND

将信号的处理函数在处理函数的入口重置为 SIG_DFL

  • SA_RESTART

重启可中断的函数而不是给出 EINTR 错误

  • SA_SIGINFO

使用 sa_sigaction 做为信号的处理函数

  • SA_NODEFER

捕获到信号时不将它添加到信号屏蔽字中

简单的代码示例如下:

#include <stdio.h>
#include <string.h>
#include <signal.h>
#define SIG SIGINT
static void
sig_handler(int sig, siginfo_t *si, void *data)
{
 printf("Caught signal: %d\n", sig);
 printf("Sender pid: %d\n", si->si_pid);
 printf("Sender uid: %d\n", si->si_uid);
}
static int
sig_caught(int sig)
{
 printf("Start caught signal: %d\n", sig);
 struct sigaction sa;
 sa.sa_flags = SA_SIGINFO;
 sa.sa_sigaction = sig_handler;
 sigemptyset(&sa.sa_mask);
 int ret = sigaction(sig, &sa, NULL);
 if (ret == -1) {
 printf("Failed to caught signal: %d\n", sig);
 return -1;
 }
 return 0;
}
int
main(int argc, char *argv[])
{
 if (sig_caught(SIG) == -1) {
 return -1;
 }
 printf("Caught signal(%d), input 'quit' to exit...\n", SIG);
 char buf[1024] = {0};
 while(1) {
 printf("Please input: ");
 scanf("%s", buf);
 if (strcmp(buf, "quit") == 0) {
 break;
 }
 }
 printf("Exit...\n");
 return 0;
}

信号屏蔽字

考虑一下这种情况:在 signal()/sigaction() 返回之前进程就已经收到了需要处理的信号,此时进程会以默认行为来处理,这显然不符合我们的期望。 这时就需要用到信号屏蔽字了,在进程启动时就将需要处理的信号加入的屏蔽字中,等 signal()/sigaction() 返回后再解除屏蔽,解除屏蔽后至少会将收到的待处理信号发送一个给进程。

屏蔽字用到一下函数:

int sigemptyset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigprocmask(int how, const sigset_t *restrict set,
 sigset_t *restrict oset);

sigprocmaskset 为需要设置的屏蔽字集, oset 为之前的屏蔽字集, how 控制着 set 如何生效,可设置为以下值:

  • SIG_BLOCK

该进程的屏蔽字集将为当期屏蔽字集与 set 的并集, set 中包含了需要屏蔽的信号集

  • SIG_UNBLOCK

该进程的屏蔽字集将为当期屏蔽字集与 set 的补集的交集, set 中包含了需要解除屏蔽的信号集

  • SIG_SETMASK

该进程的屏蔽字集将设置为 set 的值

简单的设置流程如下:

int
sig_block(int sig, int how)
{
 sigset_t mask;
 sigemptyset(&mask)
 sigaddset(&mask, sig);
 sigprocmask(how, &mask, NULL);
}

信号发送

信号可以通过 kill 函数发送给指定进程,也可以通过 raise 或者 alarm 函数发送给当前执行的线程或进程,下面来分别说说这几个函数。

kill 函数

原型:

int kill(pid_t pid, int sig);

kill 函数向指定进程发送指定的信号,如果信号为 0 将执行错误检查,信号并不会发送,可以用来检查 pid 的有效性。

pid 大于 0 时信号将发送给此进程, pid 小于等于 0 时,如下:

  • 等于 0

信号将发送给发送者所在组里的所有进程

  • 等于 -1

信号将发送给所有进程

  • 小于 -1

信号将发送给进程组为 pid 绝对值的所有组内进程

alarm 函数

原型:

unsigned alarm(unsigned seconds);

alarm 函数将在指定的 seconds 之后发送一个 SIGALRM 信号,如果 seconds 为 0, 则取消之前的定时器请求。如果不为 0 则取消之前的请求,重新设置为 seconds 。 如果在等待结束之前有其他的事件产生,那定时器请求也将被取消。

简单的代码示例如下:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
static void
handler(int sig)
{
 printf("alarm arrived: %d\n", sig);
}
int
main(int argc, char *argv[])
{
 signal(SIGALRM, handler);
 alarm(2);
 sleep(2);
 printf("alarm 5s over\n");
 alarm(10);
 sleep(1);
 unsigned int remaining = alarm(3);
 printf("alarm 10s remain: %u, reset to 3\n", remaining);
 sleep(3);
 printf("alarm 3s over\n");
 alarm(20);
 sleep(3);
 remaining = alarm(0);
 printf("cancel alarm 20s, remian: %u, exit...\n", remaining);
}

raise 函数

原型:

int raise(int sig);

raise 函数将给当前执行的线程或进程发送信号,如果信号处理函数已经被调用, raise 函数将等待信号处理函数调用结束才返回。

结语

信号处理函数是会被重复调用的,所以必要保存其是可重入的,注意处理逻辑。

另外本文中的代码都在 https://github.com/jouyouyun/examples/tree/master/signal 中,这个 repo 也有其它的示例,有兴趣的可以看看。

附录

信号表

/* ISO C99 signals. */
#define SIGINT 2 /* Interactive attention signal. */
#define SIGILL 4 /* Illegal instruction. */
#define SIGABRT 6 /* Abnormal termination. */
#define SIGFPE 8 /* Erroneous arithmetic operation. */
#define SIGSEGV 11 /* Invalid access to storage. */
#define SIGTERM 15 /* Termination request. */
/* Historical signals specified by POSIX. */
#define SIGHUP 1 /* Hangup. */
#define SIGQUIT 3 /* Quit. */
#define SIGTRAP 5 /* Trace/breakpoint trap. */
#define SIGKILL 9 /* Killed. */
#define SIGBUS 10 /* Bus error. */
#define SIGSYS 12 /* Bad system call. */
#define SIGPIPE 13 /* Broken pipe. */
#define SIGALRM 14 /* Alarm clock. */
/* New(er) POSIX signals (1003.1-2008, 1003.1-2013). */
#define SIGURG 16 /* Urgent data is available at a socket. */
#define SIGSTOP 17 /* Stop, unblockable. */
#define SIGTSTP 18 /* Keyboard stop. */
#define SIGCONT 19 /* Continue. */
#define SIGCHLD 20 /* Child terminated or stopped. */
#define SIGTTIN 21 /* Background read from control terminal. */
#define SIGTTOU 22 /* Background write to control terminal. */
#define SIGPOLL 23 /* Pollable event occurred (System V). */
#define SIGXCPU 24 /* CPU time limit exceeded. */
#define SIGXFSZ 25 /* File size limit exceeded. */
#define SIGVTALRM 26 /* Virtual timer expired. */
#define SIGPROF 27 /* Profiling timer expired. */
#define SIGUSR1 30 /* User-defined signal 1. */
#define SIGUSR2 31 /* User-defined signal 2. */
/* Nonstandard signals found in all modern POSIX systems
 (including both BSD and Linux). */
#define SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */
/* Archaic names for compatibility. */
#define SIGIO SIGPOLL /* I/O now possible (4.2 BSD). */
#define SIGIOT SIGABRT /* IOT instruction, abort() on a PDP-11. */
#define SIGCLD SIGCHLD /* Old System V name */
/* Not all systems support real-time signals. bits/signum.h indicates
 that they are supported by overriding __SIGRTMAX to a value greater
 than __SIGRTMIN. These constants give the kernel-level hard limits,
 but some real-time signals may be used internally by glibc. Do not
 use these constants in application code; use SIGRTMIN and SIGRTMAX
 (defined in signal.h) instead. */
#define __SIGRTMIN 32
#define __SIGRTMAX __SIGRTMIN
/* Biggest signal number + 1 (including real-time signals). */
#define _NSIG (__SIGRTMAX + 1)

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码