lv5 嵌入式开发-8 信号机制(上)

news2024/12/1 9:03:48

目录

1 信号机制

2 信号的产生

3 常用信号

4 相关命令

4.1 信号相关命令 kill / killall 

4.2 信号发送 – kill / raise

4.3 定时器函数相关函数 – alarm /ualarm/ pause

4.4 信号捕捉:设置信号响应方式 – signal /sigaction,闹钟实现

4.5 子进程结束信号(使用SIGCHLD信号实现回收子进程)

4.6 练习


掌握:信号机制、常用信号、信号相关命令、信号发送、定时器、信号捕捉、信号集和信号屏蔽

1 信号机制

信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式。

linux内核通过信号通知用户进程,不同的信号类型代表不同的事件

Linux对早期的unix信号机制进行了扩展

进程对信号有不同的响应方式:

  • 缺省方式  
  • 忽略信号  
  • 捕捉信号

2 信号的产生

  • 按键产生
  • 系统调用函数产生(比如raise, kill)
  • 硬件异常
  • 命令行产生 (kill)
  • 软件条件(比如被0除,访问非法内存等)

3 常用信号

SIGCHLD              子进程 状态改变发给父进程的                                                                                

4 相关命令

4.1 信号相关命令 kill / killall 

kill [-signal] pid

默认发送SIGTERM  

-sig 可指定信号  

pid  指定发送对象  

示例:

killall [-u  user | prog]

prog  指定进程名  

user  指定用户名

4.2 信号发送 – kill / raise

#include <unistd.h>
#include <signal.h>
int kill(pid_t pid, int sig);

功能:发送信号

参数:

pid:  > 0:发送信号给指定进程

        = 0:发送信号给跟调用kill函数的那个进程处于同一进程组的进程

        < -1: 取绝对值,发送信号给该绝对值所对应的进程组的所有组员。

        = -1:发送信号给,有权限发送的所有进程

signum:待发送的信号

int raise(int sig);       //给自己发信号

给自己发信号,等价于kill(getpid(), signo);

示例

#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
int main(){
    
//    kill(24149,11);  //对进程24149,发送一个段错误信号,进程24149接收到信号报错结束
   raise(11);        //对自己的进程,发送一个段错误信号
}

4.3 定时器函数相关函数 – alarm /ualarm/ pause

int alarm(unsigned int seconds);

功能:定时发送SIGALRM给当前进程(一次性)

返回值:成功时返回上个定时器的剩余时间,失败时返回EOF  

参数:seconds 定时器的时间  

一个进程中只能设定一个定时器,时间到时产生SIGALRM

示例

#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
int main(){
    
    alarm(3);
    while(1);
}

//运行结果
linux@linux:~/Desktop$ ./alarm 
Alarm clock

重复性闹钟函数 

useconds_t ualarm(useconds_t usecs, useconds_t interval); (循环发送)

以useconds为单位,第一个参数为第一次产生时间,第二个参数为间隔产生 

发送alarm信号函数

int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);

struct itimerval {
    struct timeval it_interval;  // 闹钟触发周期
    struct timeval it_value;    // 闹钟触发时间
};

struct timeval {
    time_t      tv_sec;         /* seconds */
    suseconds_t tv_usec;        /* microseconds */
};

功能:定时的发送alarm信号

参数:

-which:

        ITIMER_REAL:以逝去时间递减。发送SIGALRM信号

        ITIMER_VIRTUAL: 计算进程(用户模式)执行的时间。 发送SIGVTALRM信号

        ITIMER_PROF: 进程在用户模式(即程序执行时)和核心模式(即进程调度用时)均计算时

                                  间。 发送SIGPROF信号

-new_value:  负责设定 timout 时间

-old_value:   存放旧的timeout值,一般指定为NULL

int pause(void);

进程一直阻塞,直到被信号中断  

被信号中断后返回-1,errno为EINTR

示例:

#include <stdio.h>  
#include <stdlib.h>
#include <unistd.h>
int main() {
   alarm(3);
   pause();
   printf(“I have been waken up!\n”);
   return 0;
}
$ ./a.out 
Alarm clock

重要:alarm经常用于实现超时检测     

4.4 信号捕捉:设置信号响应方式 – signal /sigaction,闹钟实现

信号捕捉过程:

  1. 定义新的信号的执行函数handle。
  2. 使用signal/sigaction 函数,把自定义的handle和指定的信号相关联。

signal函数

typedef void (*sighandler_t)(int);
//它使用了typedef关键字定义了一个名为sighandler_t的新类型,这个类型是一个指向函数的指针,该函数以一个整型参数作为信号值,返回值类型为void(即不返回任何值)。通过这个定义,可以方便地声明和使用信号处理函数,以对接收到的信号做出相应的处理。

sighandler_t signal(int signum, sighandler_t handler);

功能:捕捉信号执行自定义函数 

返回值:成功时返回原先的信号处理函数,失败时返回SIG_ERR

参数:

  • signo 要设置的信号类型  
  • handler 指定的信号处理函数: SIG_DFL代表缺省方式;SIG_IGN 代表忽略信号;  

示例

#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <linux/posix_types.h>

typedef void (*sighandler_t)(int);

sighandler_t oldact;

void handle(int sig){
    printf("I cath the SIGINT \n");
    signal(SIGINT,oldact);   //改回原先的信号处理,如按ctrl+c结束进程
}

int main(){

    oldact = signal(SIGINT,handle);

    while(1){

        sleep(1);
    }    


}

 

sigaction函数 

系统建议使用sigaction函数,因为signal在不同类unix系统的行为不完全一样。

int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
struct sigaction {
    void (*sa_handler)(int);
    void (*sa_sigaction)(int, siginfo_t *, void *);
    sigset_t sa_mask;
    int sa_flags;
    void (*sa_restorer)(void);
}

参数:

signum:处理的信号

act,oldact: 处理信号的新行为和旧的行为,是一个sigaction结构体

sigaction结构体成员定义如下:

sa_handler: 是一个函数指针,其含义与 signal 函数中的信号处理函数类似

sa_sigaction: 另一个信号处理函数,它有三个参数,可以获得关于信号的更详细的信息。

sa_flags参考值如下:

        SA_SIGINFO:使用 sa_sigaction 成员而不是 sa_handler 作为信号处理函数

        SA_RESTART:使被信号打断的系统调用自动重新发起。

        SA_RESETHAND:信号处理之后重新设置为默认的处理方式。

        SA_NODEFER:使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出这个信号。

re_restorer:是一个已经废弃的数据域。

示例:定时器的实现(使用alarm)

#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <linux/posix_types.h>

typedef void (*sighandler_t)(int);

sighandler_t oldact;

void handle(int sig){
   if(sig == SIGINT){
        printf("I cath the SIGINT \n");
   }else if (sig==SIGALRM){
       printf("second timer \n");
       alarm(1);
   }
    //    signal(SIGINT,oldact);
}


int main(){
    struct sigaction act;
    act.sa_handler = handle;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    sigaction(SIGINT,&act,NULL);
    alarm(1);
    sigaction(SIGALRM,&act,NULL);
//    oldact = signal(SIGINT,handle);

    while(1){
        sleep(1);
    }

} 

 示例:定时器的实现(settimer实现)

#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <linux/posix_types.h>
#include <sys/time.h>


typedef void (*sighandler_t)(int);

sighandler_t oldact;

void handle(int sig){
   if(sig == SIGINT){
        printf("I cath the SIGINT \n");
   }else if (sig==SIGALRM){
       printf("second timer \n");
//       alarm(1);
   }
    //    signal(SIGINT,oldact);
}


int main(){
    struct sigaction act;
    act.sa_handler = handle;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
//    sigaction(SIGINT,&act,NULL);
//    alarm(1);
    struct itimerval timevalue;
    timevalue.it_interval.tv_sec = 1;
    timevalue.it_interval.tv_usec = 0;
    timevalue.it_value.tv_sec = 5;
    timevalue.it_value.tv_usec = 0;

    setitimer(ITIMER_REAL,&timevalue, NULL);
    sigaction(SIGALRM,&act,NULL);
//    oldact = signal(SIGINT,handle);

    while(1){
  //      sleep(1);   //sleep也是用alarm实现的
    }

} 

示例

// 头文件省略
void handler (int signo) {
     if (signo == SIGINT) {
        printf(“I have got SIGINT!\n”); }
     if (signo == SIGQUIT) {
        printf(“I have got SIGQUIT\n”); }
}

int  main() {
     signal(SIGINT, handler);
     signal(SIGQUIT, handler);
     while ( 1 ) pause();
     return 0;
}

4.5 子进程结束信号(使用SIGCHLD信号实现回收子进程)

SIGCHLD的产生条件

1子进程终止时

2子进程接收到SIGSTOP信号停止时

3子进程处在停止态,接受到SIGCONT后唤醒时

SIGCHLD

可以用来处理子进程退出的僵尸

之前是使用wait来回收,现在使用信号来配合wait回收,解决父进程阻塞的问题

示例:

#include <stdio.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>


void handle(int sig){

    wait(NULL);
    printf("Get sig =%d\n",sig);

}


int main(){
    pid_t pid;
    struct sigaction act;
    act.sa_handler = handle;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);

    pid = fork();

    if(pid>0){
        //wait(NULL);   //利用信号处理,可以让父进程异步操作,接着干自己的事情而不阻塞

        sigaction(SIGCHLD,&act,NULL);
        while(1){
            printf("this is father process\n");
            sleep(1);
        }

    }else if(pid==0){
        sleep(5);
        exit(0);
    }


}

执行完通过ps 命令查看,没有僵尸进程。

4.6 练习

实现捕捉SIGINT信号,在屏幕上打印 "Ctrl + c"

#include <stdlib.h>
#include <string.h>
#include <linux/posix_types.h>

typedef void (*sighandler_t)(int);

sighandler_t oldact;

void handle(int sig){
    printf("Ctrl+C\n");
    //signal(SIGINT,oldact);   //改回原先的信号处理,按ctrl+c结束进程
}

int main(){

    oldact = signal(SIGINT,handle);

    while(1){

        sleep(1);
    }    


}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1051560.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CCF CSP认证 历年题目自练Day14

CCF CSP认证 历年题目自练Day14 题目一 小明今天生日&#xff0c;他有n块蛋糕要分给朋友们吃&#xff0c;这n块蛋糕&#xff08;编号为1到n&#xff09;的重量分别为a1, a2, …, an。小明想分给每个朋友至少重量为k的蛋糕。小明的朋友们已经排好队准备领蛋糕&#xff0c;对于…

【进阶C语言】动态内存分配

本章大致内容介绍&#xff1a; 1.malloc函数和free函数 2.calloc函数 3.realloc函数 4.常见错误案例 5.笔试题详解 6.柔性数组 一、malloc和free 1.malloc函数 &#xff08;1&#xff09;函数原型 函数参数&#xff1a;根据用户的需求需要开辟多大的字节空间&#xff…

nodejs+vue 网上招聘系统elementui

第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;技术背景 5 3.2.2经济可行性 6 3.2.3操作可行性&#xff1a; 6 3.3 项目设计目标与原则 6 3.4系统流程分析 7 3.4.1操作流程 7 3.4.2添加信息流程 8 3.4.3删除信息流程 9 第4章 系统设计 11 …

【PyTorch实战演练】使用Cifar10数据集训练LeNet5网络并实现图像分类(附代码)

文章目录 0. 前言1. Cifar10数据集1.1 Cifar10数据集下载1.2 Cifar10数据集解析 2. LeNet5网络2.1 LeNet5的网络结构2.2 基于PyTorch的LeNet5网络编码 3. LeNet5网络训练及输出验证3.1 LeNet5网络训练3.2 LeNet5网络验证 4. 完整代码4.1 训练代码4.1 验证代码 0. 前言 按照国际…

Spring Boot 常用注解详解:全面指南

Spring Boot 中有许多常用的注解&#xff0c;这些注解用于配置、管理和定义 Spring Boot 应用程序的各个方面。以下是这些注解按大类和小类的方式分类&#xff0c;并附有解释和示例。 一、Spring Boot 核心注解 SpringBootApplication 解释&#xff1a;这是一个组合注解&a…

反射学习笔记

反射学习笔记 一、反射入门案例 在反射中&#xff0c;万物皆对象&#xff0c;方法也是对象。反射可以在不修改源码的情况下&#xff0c;只需修改配置文件&#xff0c;就能实现功能的改变。 实体类 /*** 动物猫类*/ public class Cat {private String name;public void hi()…

openGauss学习笔记-84 openGauss 数据库管理-内存优化表MOT管理-内存表特性-MOT部署服务器优化:x86

文章目录 openGauss学习笔记-84 openGauss 数据库管理-内存优化表MOT管理-内存表特性-MOT部署服务器优化&#xff1a;x8684.1 BIOS84.2 操作系统环境设置84.3 网络 openGauss学习笔记-84 openGauss 数据库管理-内存优化表MOT管理-内存表特性-MOT部署服务器优化&#xff1a;x86 …

大学各个专业介绍

计算机类 五米高考-计算机类 注&#xff1a;此处平均薪酬为毕业五年平均薪酬&#xff0c;薪酬数据仅供参考 来源&#xff1a; 掌上高考 电气类 五米高考-电气类 机械类 五米高考-机械类 电子信息类 五米高考-电子信息类 土木类 五米高考-土木类

Cloudflare进阶技巧:缓存利用最大化

1. 引言 cloudflare我想你应该知道是什么&#xff0c;一家真正意义上免费无限量的CDN&#xff0c;至今未曾有哥们喷它的。当然&#xff0c;在国内的速度确实比较一般&#xff0c;不过这也不能怪它。 CDN最大的特色&#xff0c;我想就是它的缓存功能&#xff0c;达到防攻击&am…

【数据结构】归并排序、基数排序算法的学习知识点总结

目录 1、归并排序 1.1 算法思想 1.2 代码实现 1.3 例题分析 2、基数排序 2.1 算法思想 2.2 代码实现 2.3 例题分析 1、归并排序 1.1 算法思想 归并排序是一种采用分治思想的经典排序算法&#xff0c;通过将待排序数组分成若干个子序列&#xff0c;将每个子序列排序&#xff…

安卓玩机-----给app加注册码 app加弹窗 云注入弹窗

在对接很多工作室业务中有些客户需要在他们自带的有些app中加注册码或者验证码的需求。其实操作起来也很简单。很多反编译软件有自带的注入功能。例如注入弹窗。这个是需要对应的注册码来启动应用。而且是随机id。重新安装app后需要重新注册才可以继续使用&#xff0c;原则上可…

Ubuntu 20.04部署Promethues

sudo lsb_release -r可以看到操作系统版本是20.04&#xff0c;sudo uname -r可以看到内核版本是5.5.19。 sudo wget -c https://github.com/prometheus/prometheus/releases/download/v2.37.1/prometheus-2.37.1.linux-amd64.tar.gz下载必要的组件。 tar -zxf prometheus-2.…

python对RabbitMQ的简单使用

原文链接&#xff1a;https://blog.csdn.net/weixin_43810267/article/details/123914324 RabbitMq 是实现了高级消息队列协议&#xff08;AMQP&#xff09;的开源消息代理中间件。消息队列是一种应用程序对应用程序的通行方式&#xff0c;应用程序通过写消息&#xff0c;将消…

日常学习之:如何基于 OpenAI 构建自己的向量数据库

文章目录 原理前期准备依赖安装Pinecone 数据库注册Index 创建&#xff08;相当于传统数据库中的创建 table&#xff09; 基于 pinecone 数据库的代码实现尝试用 OpenAI 的 API 构建 embedding将示例的数据 embedding 后写入你的 pinecode &#xff08;构建向量数据库&#xff…

【三次握手、四次挥手】TCP建立连接和断开连接的过程、为什么需要三次握手,为什么需要四次挥手、TCP的可靠传输如何保证、为什么需要等待2MSL等重点知识汇总

目录 三次握手 为什么握手需要三次 四次挥手 为什么挥手需要四次 TCP的可靠传输如何保证 TIME_WAIT等待的时间是2MSL 三次握手 三次握手其实就是指建立一个TCP连接。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的…

【【萌新的RISCV学习之流水线通路的控制-8】】

萌新的RISCV学习之流水线通路的控制-8 我们在之前学习了整个单周期的模块工作流程 我们按照整体的思路分段 将数据通路划分为5个阶段 IF &#xff1a; 取地址 ID &#xff1a;指令译码和读存储器堆 EX :执行或计算地址 MEM : 数据存储器访问 WB : 写回 单周期数据通路&…

Three.js加载360全景图片/视频

Three.js加载360全景图片/视频 效果 原理 将全景图片/视频作为texture引入到three.js场景中将贴图与球形网格模型融合&#xff0c;将球模型当做成环境容器使用处理视频时需要以dom为载体&#xff0c;加载与控制视频动作每次渲染时更新当前texture&#xff0c;以达到视频播放效…

强化学习到底是什么?它是怎么运维的

https://mp.weixin.qq.com/s/LL3HfU2iNlmSqaTX_3J7fQ 强化学习是一种行为学习模型,由算法提供数据分析反馈,引导用户逐步获取最佳结果。 来源丨Towards Data Science 作者丨Jair Ribeiro 编译丨科技行者 强化学习属于机器学习中的一个子集,它使代理能够理解在特定环境中…

TensorFlow入门(四、数据流向机制)

session与"图"工作过程中存在的两种数据的流向机制,即:注入机制和取回机制 注入机制(feed):即通过占位符向模式中传入数据 取回机制(fetch):指在执行计算图时&#xff0c;可以同时获取多个操作节点的计算结果 实例代码如下: import tensorflow.compat.v1 as tftf…

【Java】建筑工地智慧管理系统源码

智慧工地系统运用物联网信息技术&#xff0c;致力于推动建筑工程行业的建设发展&#xff0c;做到全自动、信息化&#xff0c;智能化的全方位智慧工地&#xff0c;实现工程施工可视化智能管理以提高工程管理信息化水平。 智慧工地平台拥有一整套完善的智慧工地解决方案&#xff…