信号发送:Linux中发送信号的四种方式(系统调用、定时器)

产生进程信号有四种方式,其中一部分已经在“了解Linux中的信号”、“信号崩溃的原因”提到了,下面是做一个总结

— 键盘发送                           — 软件条件发送             

— 系统调用发送                   — 进程异常,OS发送

但是我们需要知道一件事:OS不会相信任何人,自己动手操作最放心,所以发送信号的本质是OS来发送


目录

一、键盘发送

二、进程异常发送

三、系统调用函数发送

1、kill函数:给任意进程发送信号

2、raise函数:给当前进程发送信号

3、abort: 使当前进程收到信号而异常终止(异常中止当前进程)

四、软条件发送

1、因操作导致条件不满足

2、系统层面设置定时器


一、键盘发送

Ctrl + C发送2号信号,默认处理方式是中止进程;Ctrl + \ 发送3号信号,默认处理方式是中止进程并core dump。验证过程详见下面的博客

进程信号 —— 信号处理函数signal(了解Linux中已有的信号)_abs(ln(1+NaN))的博客-优快云博客初步了解进程信号的特点、信号处理函数signal 以及 Linux已有的信号https://blog.youkuaiyun.com/challenglistic/article/details/124413135?spm=1001.2014.3001.5501

二、进程异常发送

CPU运算过程中如果发现 诸如1/0、野指针取值的情况,这些都属于异常情况,这些异常情况会记录在状态寄存器 ——》OS会找到异常的源头进程,然后给进程发送信号 ——》这个信号不光只是中止进程的信号,还包含了异常信息(即我们平时看到的错误信息)

进程崩溃的根本原因(结合底层分析)_abs(ln(1+NaN))的博客-优快云博客了解进程崩溃的原因,并通过core dump生成的文件知道哪一行崩溃了https://blog.youkuaiyun.com/challenglistic/article/details/124480829?spm=1001.2014.3001.5501

三、系统调用函数发送

Linux给我们提供了发送信号的系统调用函数,下面就逐一来了解这些函数

1、kill函数:给任意进程发送信号

下面是kill函数的声明以及需要用到的头文件

(1) 参数、返回值解析

第一个参数是目标进程的pid,也就是要给哪个进程发送信号

第二个参数是信号ID,也就是要给目标进程发送几号信号

返回值:成功时返回0,调用失败返回-1

(2) 函数调用

这里就不创建其他进程,直接就给当前进程发送2号信号。

 

2、raise函数:给当前进程发送信号

(1) 参数、返回值解析

参数表示要给当前进程发送几号信号

返回值:成功时返回0,调用失败返回-1

(2) 函数调用

下面演示给当前进程发送3号信号

3、abort: 使当前进程收到信号而异常终止(异常中止当前进程)

下面是abort函数的声明及其需要的头文件,abort函数实际上是给当前进程发送6号信号

四、软条件发送

系统层面设置定时器 或者 某种操作导致条件不满足的时候,OS会给对应的进程发送信号

1、因操作导致条件不满足

最典型的就是前面命名管道那一部分,读端不读了,而且还退出进程了,这个时候写端还在傻乎乎的往管道里写,这不是明摆着浪费资源么。由于不满足 “读端和写端都连接到管道” 这个条件,这个时候OS就会给写端发送13号信号SIGPIPE!

2、系统层面设置定时器

Linux提供了一个到点发送14号信号的函数 alarm函数,14号信号的作用是中止当前进程

 函数参数:设置 多少秒以后给当前进程发送一个alarm信号

函数返回值:距离发送信号还剩下多少秒

### Linux中利用定时器信号中断串口发送操作的方法 在Linux环境中实现通过定时器信号中断串口发送的操作涉及多个方面,包括设置定时器、注册信号处理器以及编写相应的逻辑来控制串口通信。下面提供一种可能的方式。 #### 定义并初始化定时器 为了创建一个能够发出SIGALRM信号定时器,可以采用`timer_create()`函数[^1]: ```c #include <signal.h> #include <time.h> struct sigevent sev; sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIGALRM; timer_t timerid; if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1) { perror("Failed to create timer"); } ``` 此段代码用于建立一个新的POSIX实时定时器,并指定其触发时产生的信号为SIGALRM。 #### 配置定时器参数 接着配置定时器的时间间隔和初始超时时间,以便按照预期频率触发中断事件: ```c struct itimerspec its; its.it_value.tv_sec = 0; /* 初始延迟 */ its.it_value.tv_nsec = 5000000L;/* 即使秒数设为零也要设定纳秒值*/ its.it_interval.tv_sec = 0; /* 周期性重发周期 */ its.it_interval.tv_nsec = 5000000L; if (timer_settime(timerid, 0, &its, NULL) == -1){ perror("Failed to arm the timer"); } ``` 这里设置了定时器首次启动后的等待时间和之后每次重新计时之前的间歇。 #### 注册信号处理程序 当定时器到期后将会向进程发送SIGALRM信号,在接收该信号之前需先定义好对应的处理方法: ```c void handle_alarm(int signum) { printf("Caught signal %d\n",signum); // 这里放置停止UART传输的具体指令 } // 将handle_alarm绑定到SIGALRM信号上 struct sigaction sa; sa.sa_handler = &handle_alarm; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART | SA_NODEFER; if(sigaction(SIGALRM,&sa,NULL)==-1){ perror("Error setting signal handler"); } ``` 上述代码片段展示了如何捕捉来自定时器的报警信号,并执行特定的任务——即终止当前正在进行中的UART数据流。 #### 控制串口设备 对于具体的串口读写操作,则依赖于termios库所提供的接口来进行配置与管理;而要暂停或恢复这些活动则可通过关闭/开启相应文件描述符上的O_NONBLOCK标志位完成: ```c int fd=open("/dev/ttyS0", O_RDWR|O_NOCTTY); /* ...省略掉一些必要的初始化工作... */ // 关闭非阻塞模式以允许正常的数据交换过程发生 fcntl(fd,F_SETFL,flockfile&~O_NONBLOCK); // 当alarm()被调用时,可在此处加入额外措施确保已安全地中止任何未决I/O请求 close(fd); ``` 以上就是关于怎样借助Linux下的定时器机制去影响串行端口行为的一个基本框架说明[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值