【linux学习指南】Linux进程信号产生(二)软件中断

news2024/11/30 11:32:05

请添加图片描述

文章目录

  • 📝 由软件条件产⽣信号
  • 🌠 基本alarm验证-体会IO效率问题
    • 🌉设置重复闹钟
  • 🌠如何理解软件条件
    • 🌉如何简单快速理解系统闹钟
  • 🚩总结


📝 由软件条件产⽣信号

SIGPIPE 是⼀种由软件条件产⽣的信号,在“管道”中已经介绍过了。本节主要介绍和SIGALRM 信号。

NAME
       alarm - set an alarm clock for delivery of a signal

SYNOPSIS
       #include <unistd.h>

       unsigned int alarm(unsigned int seconds);

DESCRIPTION
       alarm() arranges for a SIGALRM signal to be delivered to the calling process in seconds seconds.

       If seconds is zero, any pending alarm is canceled.

       In any event any previously set alarm() is canceled.

RETURN VALUE
       alarm() returns the number of seconds remaining until any previously scheduled alarm was due to be deliv‐
       ered, or zero if there was no previously scheduled alarm.

调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发SIGALRM信号,该信号的默认处理动作是终止当前进程。

这个函数的返回值是0或者是以前设定的闹钟时间还余下的秒数。打个⽐⽅,某⼈要⼩睡⼀觉,设定闹
钟为30分钟之后响,20分钟后被⼈吵醒了,还想多睡⼀会⼉,于是重新设定闹钟为15分钟之后响,“以
前设定的闹钟时间还余下的时间”就是10分钟。如果seconds值为0,表⽰取消以前设定的闹钟,函数
的返回值仍然是以前设定的闹钟时间还余下的秒数。

🌠 基本alarm验证-体会IO效率问题

程序的作⽤是1秒钟之内不停地数数,1秒钟到了就被SIGALRM信号终⽌。必要的时候,对SIGALRM信号进⾏捕捉

  1. IO 多,因频繁往我们的显示器文件进行写入操作
//IO 多
 #include <iostream>
 #include <unistd.h>
 #include <signal.h>
int main()
{
    int count = 0;
    alarm(1);
    while(true)
    {
        std::cout<< "count : "<< count <<std::endl;
        count++;
    }

    return 0;
}

在这里插入图片描述

  1. IO 少:过一秒后收到alarm的信号再通过特定的处理函数可以进行一次写入显示器文件
 #include <iostream>
 #include <unistd.h>
 #include <signal.h>
int count = 0;

void handler(int signumber)
{
    std::cout<< " count: "<<count<<std::endl;
    exit(0);
}
int main()
{

    signal(SIGALRM, handler);
    alarm(1);
    while(true)
    {
        count++;
    }
    return 0;
}

由23W的次数,增强到5亿次,可见频繁的进行IO会减少很高的效率
在这里插入图片描述
结论:

  • 闹钟会响⼀次,默认终⽌进程
  • 有IO效率低

🌉设置重复闹钟

#include <iostream>
#include <string>
#include <sys/types.h>
#include <unistd.h>
#include <wait.h>
#include <signal.h>
#include <vector>
#include <functional>
using func_t = std::function<void()>;

int gcount = 0;
std::vector<func_t> gfuncs;

//把信号更换成为硬件中断
void handler(int signo)
{
    for(auto& f: gfuncs)
    {
        f();
    }

    std::cout<< "gcount: "<<gcount <<std::endl;
    // int n = alarm(1);//重设闹钟,会返回上一次闹钟的剩余时间
    // std::cout<<"剩余时间:"<< n <<std::endl;
}

int main()
{
    gfuncs.push_back([](){
        std::cout<< "我是一个内核刷新操作"<<std::endl;
    });

    gfuncs.push_back([](){
        std::cout<< "我是⼀个检测进程时间⽚的操作,如果时间⽚到了,我会切换进程"<<std::endl;
    });

    gfuncs.push_back([](){
        std::cout<< "我是⼀个内存管理操作,定期清理操作系统内部的内存碎⽚"<<std::endl;
    });

    alarm(1);//一次性闹钟,超时alarm会自动被取消
    signal(SIGALRM, handler);

    while(true)
    {
        pause();
        std::cout<< "我醒来了..." <<std::endl;
        gcount++;
    }

    return 0;
}

程序运行一次,就暂停了,当一个进程调用pause函数时,它会使该进程进入睡眠状态(阻塞状态),并暂停执行后续的代码,直到该进程接收到一个信号并从该信号的处理程序中返回。也就是说,pause函数实际上是在等待一个信号来中断当前的暂停状态,使进程能够继续往下执行。
在这里插入图片描述
我们可以在handler函数中在设置一个alarm,形成发送取消中断信号,重新运行:

#include <iostream>
#include <string>
#include <sys/types.h>
#include <unistd.h>
#include <wait.h>
#include <signal.h>
#include <vector>
#include <functional>

using func_t = std::function<void()>;

int gcount = 0;
std::vector<func_t> gfuncs;

//把信号更换成为硬件中断
void handler(int signo)
{
    for(auto& f: gfuncs)
    {
        f();
    }

    std::cout<< "gcount: "<<gcount <<std::endl;
    int n = alarm(1);//重设闹钟,会返回上一次闹钟的剩余时间
    std::cout<<"剩余时间:"<< n <<std::endl;
}

int main()
{
    gfuncs.push_back([](){
        std::cout<< "我是一个内核刷新操作"<<std::endl;
    });

    gfuncs.push_back([](){
        std::cout<< "我是⼀个检测进程时间⽚的操作,如果时间⽚到了,我会切换进程"<<std::endl;
    });

    gfuncs.push_back([](){
        std::cout<< "我是⼀个内存管理操作,定期清理操作系统内部的内存碎⽚"<<std::endl;
    });

    alarm(1);//一次性闹钟,超时alarm会自动被取消
    signal(SIGALRM, handler);

    while(true)
    {
        pause();
        std::cout<< "我醒来了..." <<std::endl;
        gcount++;
    }

    return 0;
}

再次运行,会进行死循环操作流程:
1.main函数进来设置alarm一秒,然后通过signal设置alarm的处理方式从终止改为handler,然后进入while(true)执行pause()暂停循环;当一秒到来,执行handler函数,等到handler里的alarm函数再次设置启动,pause()收到取消睡眠状态信号,再次运行这个1秒。接下来就是往复复的动作了。
在这里插入图片描述

结论:

  • 闹钟设置⼀次,起效⼀次
  • 重复设置的⽅法
  • alarm(0):如果seconds值为0,表⽰取消以前设定的钟,函数的返回值仍然是以前设定的闹钟时间还余下的秒数

🌠如何理解软件条件

在操作系统中,信号的软件条件指的是由软件内部状态或特定软件操作触发的信号产⽣机制。这些条件包括但不限于定时器超时(如alarm函数设定的时间到达)、软件异常(如向已关闭的管道写数据产⽣的SIGPIPE信号)等。当这些软件条件满⾜时,操作系统会向相关进程发送相应的信号,以通知进程进⾏相应的处理。简⽽⾔之,软件条件是因操作系统内部或外部软件操作⽽触发的信号产⽣。

🌉如何简单快速理解系统闹钟

系统闹钟,其实本质是OS必须⾃⾝具有定时功能,并能让⽤⼾设置这种定时功能,才可能实现闹钟这
样的技术。
现代Linux是提供了定时功能的,定时器也要被管理:先描述,在组织。内核中的定时器数据结构是:

struct timer_list
{
    struct list_head entry;
    unsigned long expires;
    void (*function)(unsigned long)
    unsigned long data;

    struct tvec_t_base_s *base;
};

我们不在这部分进行深究,为了理解它,我们可以看到:定时器超时时间expires和处理方法function

操作系统管理定时器,采用的是时间轮的做法,但是我们为了简单理解,可以把它在组织成为"堆结构"(小堆排序,处理时间短的节点)。


🚩总结

请添加图片描述

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

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

相关文章

蓝桥杯每日真题 - 第24天

题目&#xff1a;&#xff08;货物摆放&#xff09; 题目描述&#xff08;12届 C&C B组D题&#xff09; 解题思路&#xff1a; 这道题的核心是求因数以及枚举验证。具体步骤如下&#xff1a; 因数分解&#xff1a; 通过逐一尝试小于等于的数&#xff0c;找到 n 的所有因数…

python学opencv|读取图像

【1】引言 前序学习了使用matplotlib模块进行画图&#xff0c;今天开始我们逐步尝试探索使用opencv来处理图片。 【2】学习资源 官网的学习链接如下&#xff1a; OpenCV: Getting Started with Images 不过读起来是英文版&#xff0c;可能略有难度&#xff0c;所以另推荐一…

ROS2教程 - 2 环境安装

更好的阅读体验&#xff1a;https://www.foooor.com 2 环境安装 下面以 ROS2 的 humble 版本为例&#xff0c;介绍 ROS2 的安装。 ROS1 只能在 ubuntu 系统上安装&#xff0c;ROS2全面支持三种平台&#xff1a;Ubuntu、MAC OS X、Windows10&#xff0c;下面在 Ubuntu22.04 …

神经网络入门实战:(六)PyTorch 中的实用工具 SummaryWriter 和 TensorBoard 的说明

(一) SummaryWriter 这里先讲解 SummaryWriter &#xff0c;TensorBoard 会在第二大点进行说明。 SummaryWriter 是 PyTorch 中的一个非常实用的工具&#xff0c;它主要用于将深度学习模型训练过程中的各种日志和统计数据记录下来&#xff0c;并可以与 TensorBoard 配合使用&am…

git的使用(简洁版)

什么是 Git&#xff1f; Git 是一个分布式版本控制系统 (DVCS)&#xff0c;用于跟踪文件的更改并协调多人之间的工作。它由 Linus Torvalds 在 2005 年创建&#xff0c;最初是为了管理 Linux 内核的开发。Git 的主要目标是提供高效、易用的版本控制工具&#xff0c;使得开发者…

联想M7400Pro打印机报无法打印02 关闭电源,然后重新打开。故障检修分析

联想M7400Pro打印机无法打印02可能是由于硬件故障、软件问题、通信故障等引起的。 以下是故障的解决方法: 1、关闭打印机(可尝试多次重新启动打印机)。 2、重新放置碳粉盒组件。 3、检查打印机驱动程序是否已正确安装。 4、检查打印机的设置,确保已选择正确的打印模式…

排序(数据结构)

排序&#xff1a; 所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 常见排序法 . 常见排序算法的实现 插入排序 1.直接插入排序 2.希尔排序( 缩小增量排序&#xff09; 希尔排序的特性总结&#x…

【深度学习】铝箔表面缺陷检测【附链接】

一、铝箔表面缺陷种类 铝箔广泛应用于食品包装、药品包装和工业用途等领域&#xff0c;表面质量直接影响产品的性能和安全性。铝箔表面常见的缺陷主要包括&#xff1a; 划痕&#xff1a;铝箔在生产、加工或运输过程中可能会出现划痕&#xff0c;影响外观和功能。 气泡&#x…

OpenCV 图像轮廓查找与绘制全攻略:从函数使用到实战应用详解

摘要&#xff1a;本文详细介绍了 OpenCV 中用于查找图像轮廓的 cv2.findContours() 函数以及绘制轮廓的 cv2.drawContours() 函数的使用方法。涵盖 cv2.findContours() 各参数&#xff08;如 mode 不同取值对应不同轮廓检索模式&#xff09;及返回值的详细解析&#xff0c;搭配…

AI之Data之Label Tool:Label Studio(多类型数据标注工具)的简介、安装和使用方法、案例应用之详细攻略

AI之Data之Label Tool&#xff1a;Label Studio(多类型数据标注工具)的简介、安装和使用方法、案例应用之详细攻略 目录 Label Studio的简介 1、特点 Label Studio的安装和使用方法&#xff1a; 1、Label Studio 提供多种安装方式 T1、使用Docker安装 T2、使用pip安装&am…

【Linux相关】服务器无网情况配置conda

【Linux相关】 服务器无网情况配置conda 文章目录 环境配置1. 本地下载miniconda&#xff0c;传到服务器2. 确认安装包是否传送成功3. 确保有安装权限4. 安装5. 写路径6. 看一下是否成功 环境配置 ssh的话&#xff0c;服务器连不上网&#xff0c;无法在线下载&#xff0c;需要本…

Redis使用场景-缓存-缓存穿透

前言 之前在针对实习面试的博文中讲到Redis在实际开发中的生产问题&#xff0c;其中缓存穿透、击穿、雪崩在面试中问的最频繁&#xff0c;本文加了图解&#xff0c;希望帮助你更直观的了解缓存穿透&#x1f600; &#xff08;放出之前写的针对实习面试的关于Redis生产问题的博…

Docker desktop 改变存储位置

项目场景&#xff1a; 在windows下&#xff0c;使用docker desktop是使用docker最简单直接的方式。但是&#xff0c;这毕竟是一个可视化的界面&#xff0c;使用起来还是和linux环境下的版本有很大的区别。 例如&#xff0c;使用docker desktop&#xff0c;会默认将镜像以及容…

[CA] 尝试深入理解core.cpp -1

#我给你代码&#xff0c;你给我在源代码上额外加上中文注释&#xff01;&#xff0c;如果是函数告诉我它读取了什么结构&#xff0c;传递了什么值&#xff0c;可能或者已经知道它将在哪些函数利用&#xff0c;是体现了pipeline 的哪一步# #include "core.h" #includ…

宠物空气净化器推荐2024超详细测评 希喂VS霍尼韦尔谁能胜出

最近有粉丝一直在评论区和后台探讨宠物空气净化器是不是智商税的问题&#xff0c;有人认为宠物空气净化器肯定不是智商税&#xff0c;有些人认为将其购回家就是个没用的东西&#xff0c;还占地方&#xff0c;双方各有自己的观点。 其实宠物空气净化器和普通的空气净化器是有很大…

NeuIPS 2024 | YOCO的高效解码器-解码器架构

该研究提出了一种新的大模型架构&#xff0c;名为YOCO&#xff08;You Only Cache Once&#xff09;&#xff0c;其目的是解决长序列语言模型推理中的内存瓶颈。YOCO通过解码器-解码器结构的创新设计&#xff0c;显著减少推理时的显存占用并提升了长序列的处理效率。 现有大模…

《数据挖掘:概念、模型、方法与算法(第三版)》

嘿&#xff0c;数据挖掘的小伙伴们&#xff01;今天我要给你们介绍一本超级实用的书——《数据挖掘&#xff1a;概念、模型、方法与算法》第三版。这本书是数据挖掘领域的经典之作&#xff0c;由该领域的知名专家编写&#xff0c;系统性地介绍了在高维数据空间中分析和提取大量…

RT-DETR融合Inner-IoU及相关改进思路

RT-DETR使用教程&#xff1a; RT-DETR使用教程 RT-DETR改进汇总贴&#xff1a;RT-DETR更新汇总贴 《Inner-IoU: More Effective Intersection over Union Loss with Auxiliary Bounding Box》 一、 模块介绍 论文链接&#xff1a;https://arxiv.org/abs/2311.02877 代码链接&a…

解决“磁盘已插上,但Windows系统无法识别“问题

电脑上有2块硬盘&#xff0c;一块是500GB的固态硬盘&#xff0c;另一块是1000GB的机械硬盘&#xff0c;按下开机键&#xff0c;发现500G的固态硬盘识别了&#xff0c;但1000GB的机械硬盘却无法识别。后面为了描述方便&#xff0c;将"500GB的固态硬盘"称为X盘&#xf…

[2024年3月10日]第15届蓝桥杯青少组stema选拔赛C++中高级(第二子卷、编程题(2))

方法一&#xff08;string&#xff09;&#xff1a; #include <iostream> #include <string> using namespace std;// 检查是否为回文数 bool isPalindrome(int n) {string str to_string(n);int left 0, right str.size() - 1;while (left < right) {if (s…