【Linux课程学习】:第20弹---信号入门专题(基础部分)

🎁个人主页:我们的五年****

🔍系列专栏:Linux课程学习****

🌷追光的人,终会万丈光芒

🎉欢迎大家点赞👍评论📝收藏⭐文章

Linux学习笔记:

https://blog.csdn.net/djdjiejsn/category_12669243.html

前言:

信号这专题也是很重要的,对之前学过的知识再次关联起来,形成闭环,对理解Linux操作系统有很大的帮助。信号的学习包含:1.信号的产生,2.信号的保存,3.信号的处理这三方面。关于信号的保存,在没学信号之前可能不太理解,学了以后,这步是必不可少的,因为在收到信号以后,因为block,可能不会马上处理。下面我们进行详细的讲解。

目录

一.信号入门-生活角度的信号:

二.技术角度的信号:

2.1键盘Ctrl+c产生信号:

三.前台进程和后台进程

3.1前台进程:

3.2后台进程:

3.3关于前台进程和后台进程的命令:

四.信号的分类

[4.1kill -l查看所有的信号:](#4.1kill -l查看所有的信号:)

4.2信号的终止:

五.信号处理的常见方式

5.1信号处理的方式有三种:

5.2对信号进行自定义处理:

5.3对signal的应用


一.信号入门-生活角度的信号:

对于日常生活来说,平常的闹钟,语言,铃声......这些都是信号,对于如何从生活中的信号去和Linux操作系统中的信号进行联系,我引入了下面这一个例子:

在我们点好外卖以后,外卖小哥会接单,商家会处理。但是我们点好外卖以后就可以去等外卖送到门口了,我们不需要关心怎么送到的,其他等问题,我们就和外卖小哥形成了异步。等外卖到了以后,会有电话或者门铃等信号告知我们外卖来了。但是我们不会马上处理这个信号,也就是说,但是我们心中是知道有这一个信号来了的。多久处理就是看其他各种情况了。在过了一会以后,我们处理这个信号,我们可以把外卖拿进去吃,也可以拿进去不吃,也可以干脆不去拿,忽略这一个信号了(啥都不干)。所以这就是处理信号。然后处理信号之前就是信号的保存等问题了。


二.技术角度的信号:

2.1键盘Ctrl+c产生信号:

在我们启动一个shell进程,然后运行一个死循环的程序。如果我们想要这个进程(前台进程)退出,我们就可以在键盘下按下Ctrl+c(Ctrl+c其实就是2号信号,SIGINT),就可以杀死进程了。它的逻辑先是这样的:

1.键盘按Ctrl+c组合键,键盘产生一个中断。

2.这个终端被操作系统获取,其实CPU的针脚能察觉到,然后OS操作系统可以拿到这个信息。

3.OS就可以去给一个进程发信号。

发信号的本质:去改进程PCB中的pending位图。

Ctrl+c:不能终止后台进程。


三.前台进程和后台进程

|------|-----------------------|
| 前台进程 | 进程在终端用户界面中运行 |
| 后台进程 | 不占用用户的终端 |

3.1前台进程:

🍟前台进程的定义:

前台进程是用户启动并且需要保持与用户交互的进程。这些进程在终端用户界面中运行,用户可以直接控制和管理它们

🍟产生方式:

一般./test运行的就是前段进程。

🍟特点:

1.占用终端:前台进程会一直占用终端,直到它运行结束或者被暂停(如通过Ctrl+Z组合键)。在它运行期间,终端不能用于其他操作,除非暂停或终止这个前台进程

**2.对终端信号敏感:**前台进程会接收并处理终端发送的信号。例如,当用户在终端中按下Ctrl+C组合键时,前台进程会收到SIGINT(中断信号)并通常会终止运行,除非它对这个信号进行了特殊的处理(如信号捕获和忽略)。

3.状态显示:当前台进程正常运行时,在ps命令的输出中(如ps -ef)显示为R状态,表示正在运行并占用CPU资源。如果通过Ctrl+Z组合键暂停了前台进程,它的状态会变为T,表示停止运行

3.2后台进程:

🍟后台进程的定义:

后台进程是在后台运行的进程,它们不占用用户的终端,用户也不需要直接与之交互。后台进程通常用于执行一些不需要用户立即关注的任务,比如长时间的计算任务、数据备份任务、服务器的守护进程等。

🍟产生方式:

在前台进程后面加上**&符号**就是后台进程。

🍟特点:

1.不占用终端I/O:后台进程不会阻止用户在终端进行其他操作,它的输出信息(标准输出和标准错误输出)可以通过重定向的方式保存到文件中,这样就不会在终端显示,干扰用户的其他操作。例如,可以使用">output.log 2>error.log"来分别将标准输出和标准错误输出重定向到output.log和error.log文件中。
2.对信号处理方式不同:后台进程也会接收信号,但对一些信号的默认处理方式可能和前台进程不同。例如,后台进程一般不会因为Ctrl+C而终止,除非它专门对SIGINT信号进行了处理。
3.状态显示:后台进程在正常运行时也显示为R状态,不过它不会占用终端的I/O设备。和前台进程类似,后台进程也可以被暂停,状态变为T。可以使用bg命令让它在后台继续运行,或者用fg命令将其恢复到前台运行。

3.3关于前台进程和后台进程的命令:

fg //把后台进程放到前台。
bg //让暂停的后台进程继续运行。
jobs //查看前后台进程的信息

四.信号的分类

4.1kill -l查看所有的信号:

如果要查看更详细的信号信息,可以在man 7 signal中查看

下面就表示信号的分类,其实这些都是定义的宏,用数字也是一样的。

对于34号以后的信号是实时信号,我们这里不理解。主要研究的是34号以下的,1到31号。这里有31个信号,用一个int位图就能表示出来。

刚刚我们使用的信号:
1.Ctrl+c:SIGINT(2号信号)

2.Ctrl+\:SIGQUIT(3号信号)

4.2信号的终止:

信号终止一般有core和term终止。在man 7 signal中就会有详细的介绍,里面就会有是core终止还是term终止进程。

core和term终止进程基本差不多,唯一不同的就是:
如果进程发生core终止,可能会生成core文件。

但是必须是我们先把core file的大小调成大于0,这样才能生成core文件!!!

ulimit -c 1024:把core file文件改成1024字节。

ulimit -a:查看相关信息。


五.信号处理的常见方式

5.1信号处理的方式有三种:

1.忽略此信号。

2.执行该信号的默认处理动作。

3.提供一个信息处理函数,要求内核在处理这个信号的时候,切换到用户态执行这个函数,这种方式成为捕捉

5.2对信号进行自定义处理:

对信号进行自定义处理的函数是:

头文件:

#include <signal.h>

函数原型:

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

函数解释:

1.signum表示的是要对几号信号进行处理。

2.handler是一个函数指针,表示的是自定义的方式。

typedef void (*sighandler_t)(int);

它的类型是一个返回值为void,参数为int的函数指针。

也可以传这些参数:
SIG_IGN:表示的是处理信号的方式是忽略此信号

SIG_DFL:执行该信号的默认行为

5.3对signal的应用

对signal的应用,我们可以通过命令行参数,就可以在shell命令行中对指定的信号进行指定的修改。

我们还可以通过for循环对31个信号的执行方式进行修改。那么以后OS给我们写的程序的进程发的终止信号就不起作用了。

那是不是我们的进程就一直不会被杀掉呢?

答案:9号信号是不运行我们进行修改的,它的行为会一直是终止进程。所以我们的进程是肯定能被杀死的。

下面是关于signal的应用:

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>

void Handler(int signo)
{
    std::cout << "l love xy!signo:" << signo << std::endl;
}

void Uuage(std::string s)
{
    std::cout << "please use:" << std::endl;
    std::cout << s << " signo" << " pid" << std::endl;
}

int cout = 0;
void die(int signo)
{
    std::cout << " cout:" << cout << std::endl;
    abort();
}

int main(int argc, char *argv[])
{
    // 服务器,一秒可以累加多少次
    alarm(100);
    signal(SIGINT, die);
    sleep(5);
    unsigned int n = alarm(5);
    std::cout << n << std::endl;

    
    // abort();
    // std::cerr << "kill" << std::endl;
    // // raise(9);
    // if (argc != 3)
    // {
    //     Uuage(argv[0]);
    //     exit(1);
    // }

    // //-signum   信号的类型
    // int signum = std::stoi(argv[1] + 1);
    // // std::cout << signum << std::endl;

    // // pid
    // pid_t id = std::stoi(argv[2]);

    // int n = ::kill(id, signum);

    // if (n < 0)
    // {
    //     std::cerr << "kill" << std::endl;
    // }

    
    // 如果一直没有调用,那么Handler就一直不会被调用!
    // 不要放在循环中,因为只要进行说明一次,就会进行保存!

    // 九号信号是不能被捕捉的!!!
    // 不然如果把终止进程的信号全部捕捉,一个进程就不能被杀死
    // for (int i = 1; i <= 31; i++)
    // {
    //     signal(i, Handler);
    // }

    // while (1)
    // {
    //     std::cout << "pid:" << getpid() << std::endl;
    //     sleep(1);
    // }

    // int num = 0;
    // while (1)
    // {
    //     std::cout << "num:" << num << std::endl;
    //     sleep(1);
    //     ++num;
    // }
    return 0;
}

到这里文章就基本结束了,作为C++程序员,请保持持续的学习,每天的算法练习!在这里欢迎大家和我一起交流问题,共同进步。

🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷

相关推荐
小马爱打代码7 分钟前
Spring Boot集成ShedLock实现分布式定时任务
spring boot·分布式·后端
m0_7482478022 分钟前
如何使用Node.js快速创建本地HTTP服务器并实现异地远程访问
服务器·http·node.js
南宫生22 分钟前
力扣-图论-9【算法学习day.59】
java·学习·算法·leetcode·图论
confident325 分钟前
hibernate 配置 二级 缓存
java·缓存·hibernate
Eshin_Ye26 分钟前
transformer学习笔记-自注意力机制(1)
笔记·学习·transformer·attention·注意力机制
weixin_4258782329 分钟前
Nginx 缓存那些事儿:原理、配置和最佳实践
运维·nginx·缓存
ccnnlxc31 分钟前
prometheus
linux·服务器·prometheus
芜湖_41 分钟前
从〇开始深度学习(番外)——快速配置云服务器
服务器·人工智能·深度学习·pycharm·autodl
索然无味io1 小时前
SQL注入--Access注入
数据库·笔记·sql·学习·mysql·网络安全
keira6741 小时前
【21天学习AI底层概念】day2 机器学习基础
人工智能·学习·机器学习