IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 信号产生前 -> 正文阅读

[嵌入式]信号产生前

信号与信号量完全没有任何关系

信号入门

生活中还有没有信号的场景呢?
:闹钟,烽火台的烽火,鸡鸣声。。。—》都是给人看的
当我们面对这些场景的时候,我们就立马能够想到某些东西的时候,这些都是信号
信号的产生就代表上面的场景触发,
信号的产生—》信号是要给进程发的—》进程要在合适的时候,要执行对应的动作

但是,并不是这些场景真正放在我面前的时候,我才知道应该怎么做,这些场景是否被触发,没有直接的关系
因为对于信号的处理动作,我们早就知道了,甚至远远早于信号的产生
如:听的铃声响了,我们就知道下课了

我们怎么做到 呢?
我们对特定事件的反应,这是被教育的结果(本质是:我们这些都记住了)

  1. 所以进程在没有收到信号的时候,进程知道如何识别是什么信号,怎么处理这些信号
    而之前在写OS 的时候,程序员就已经设置好了
    进程具有识别信号并且处理信号的能力,远远早于信号的产生

在生活当中,我们收到某种信号的时候,并不一定被立即处理(因为信号随时都能产生,但是我当前可能做着更重要的事情,不去处理)

  1. 进程收到某种信号的时候,并不是立即处理的,而是在合适的时候才去处理,

  2. 进程收到信号之后,需要先将信号保存起来,以供在合适的时候进行对信号的处理
    我们把这个信号放在进程 的PCB 里面,所以信号本质也是数据
    信号的发送—>往进程task_struct 里面写数据

  3. task_struct 是一个内核数据结构,定义进程对象,内核不相信任何人,只相信自己!只有OS 可以往task_struct 里面写入数据(无论我们的信号如何发送,本质上都是在底层通过 OS.进行传输的)

信号产生的各种方式(信号产生前)

demo

在这里插入图片描述
kill -l可以查看信号列表
在这里插入图片描述

前31个信号是常规信号,后31个是实时信号

键盘ctrl+c的时候,本质上就是我们向进程里面发送2号信号SIGINT

signal

在这里插入图片描述
signal:可以修改进程对信号的默认处理工作
第一个参数就是我们的信号对应的宏值,我们既可以使用kill -l信号前面的数字,也可以使用宏

typedef void (*sighandler_t)(int);
函数指针,返回值为void,参数为int

#include <unistd.h>
#include<stdio.h>
#include<signal.h>

void handler(int signo)//函数名就是我们目标函数的地址,这里的signo对应的就是信号数值
{
  printf("get a signal: signo:%d\n,pid:%d\n",signo,getpid());
}
int main()
{
  //我们可以通过signal注册对2号信号(终止)处理动作,改成我们自定义的动作
  signal(2,handler);//我们对2号信号进行处理
  //注册的时候,并不会调用这个函数,只有当信号到来的时候,这个函数才会被调用
  while(1)
  {
    printf("hello world\n,pid: %d\n",getpid());
    sleep(1);
  }
  return 0;
}

在这里插入图片描述
在这里插入图片描述
我们发现我们ctrl c 或者kill 2 的话都会处理我们自己对信号的处理

我们发现信号的产生方式其中一种是通过键盘产生的
在这里插入图片描述
但是键盘产生的信号只能终止前台进程,不能处理后台进程,只能杀掉前台进程
但是我们可以

kill -9 pid

杀掉后台进程

信号处理方式概述

总结:
一般而言,收到信号的处理方式有3种

  1. 默认动作:终止自己(ctrl c)暂停(ctrl z)等
  2. 忽略动作:是一种信号处理的方式,只不过动作就是什么也不干,
  3. (信号的捕捉)自定义动作:类似我们刚刚用signal方法,就是在修改信号的处理动作,有:默认–》 自定义动作,我们可以对不同的信号设置不同的响应动作

void handler(int signo)//函数名就是我们目标函数的地址
{
  switch(signo)
  {
    case 2:
      printf("hello bite %d",signo);
      break;
    case 3:
      printf("hello world %d",signo);
      break;
    case 9:
      printf("quit");
      break;
  }
  //printf("get a signal: signo:%d\n,pid:%d\n",signo,getpid());
  //exit(1);
}

在这里插入图片描述

9号信号无法被捕捉

信号产生的方式

1

我们通过键盘对进程发送信号
ctrl c ,ctrl d, ctrl z

2

程序中存在异常问题,导致我们收到信号退出

进程崩溃的时候我们最想知道什么

当然是崩溃的原因,我收到了信号,waitpid(),status可以获取退出信号

我要解决他
崩溃的话就可以用这个方法去运行

我们得知道在哪一行崩溃了

  1. 在linux中当一个进程退出的时候,他的退出码和退出信号都会被设置(正常情况下)
  2. 当一个进程异常退出的时候,进程的退出信号会被设置,表面当前进程退出的原因
  3. 如果必要,OS 会设置退出消息中的core dump标志位,并将进程在内存中的数据传输到磁盘当中,方便后续调试

默认情况下在云服务器上core dump是被关掉的
在这里插入图片描述
我们这个core dump放开
ulimit -c 10240

在这里插入图片描述
放开之后会产生core dump文件

在这里插入图片描述

如果进程异常退出的时候,被core dump设置为1

不一定是所有信号都会被core dump

11号信号SIGSEGV

void sigtest()
{
  while(1)
  {
    int *p=NULL;
    p=(int*)100;
    *p=100;//对指针解引用,指向空间为NULL,我们是不可以写入的,进程的崩溃
  }
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

SIGSEGV段错误----》进程崩溃是因为接收到了11号信号而崩溃的,

8号信号SIGFPE

  while(1)
  {
   // int *p=NULL;
   // p=(int*)100;
   // *p=100;//对指针解引用,指向空间为NULL,我们是不可以写入的,进程的崩溃
  int a=10;
  a/=0;

  }

浮点数错误
在这里插入图片描述
在win or linux下进程崩溃的本质是进程收到了对应的信号,然后进程处理信号的默认动作(杀死进程)
但是为什么会收到信号呢?

在这里插入图片描述

3

kill

给别人发信号
通过系统调用产生信号
在这里插入图片描述
可以向特定进程发送特定信号

#include<stdio.h>
#include<sys/types.h>
#include<signal.h>
#include<stdlib.h>

void usage(const char* proc)
{
  printf("Usage:\n \t,%s,sign who\n",proc);
}

int main(int argc,char*argv[])
{
  if(argc!=3)
  {
    usage(argv[0]);
    return 1;
  }
  int signo=atoi(argv[1]);
  int who=atoi(argv[2]);
  kill(who,signo);
  printf("%d %d",signo,who);
  return 0;
}

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

raise

给自己发信号

  while(1)
  {
    printf("1");
    sleep(3);
    raise(8);//给自己发一个8号信号
  }

在这里插入图片描述

4

通过软件条件,也能产生信号
alarm相当于一个闹钟

在这里插入图片描述
在seconds秒之后给我们发送一个14号信号
在这里插入图片描述
返回值为0,或剩余的秒数

在这里插入图片描述

#include<unistd.h>
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>

int count=0;
//统计一下1s,我们的server可以对int递增到多少

void HandAlarm(int signo)
{
  printf("%d\n",count);
  exit(1);
}
int main()
{
  signal(SIGALRM,HandAlarm);//我们对14号信号进行注册一下
  //设置闹钟
  alarm(1);//我们没有设置alarm信号的捕捉动作(没有自定义调用signal函数),执行默认动作
  while(1)
  {
    count++;
    //printf("hello %d\n",count++);
  }
  return 0;
}

永远都是操作系统发送的信号

那么我们怎么理解OS给进程发送数据,task_struct ----->本质是,OS向执行进程的task_struct 中的信号位图写入比特位1,即完成了信号的发送–>信号的写入

信号的编号是有规律的[1,31]

struct task_struct 
{
//进程的各种属性
//进程内部一定要有对应的数据变量,来保存是否收到了对应的信号,

}

我们用什么数据变量来标识是否收到了信号,
uint32_t sigs:一定会存在位图结构
0000 0000 0000 0000 0000 0000 0000 0000
我们认为左大,右边第一个是第一个比特位,
所谓的比特位的位置(第几个),代表的就是哪一个信号,比特位的内容(0,1)代表的就是是否收到了信号
0000 0000 0000 0000 0000 0000 0000 0101
当前进程收到了1号信号,3 号信号,

在进程中采用位图,来标识该进程是否收到信号,

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-05-05 11:35:52  更:2022-05-05 11:37:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/30 1:05:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码