最后的话
最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!
资料预览
给大家整理的视频资料:
给大家整理的电子书资料:
如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
可以看到当这个程序运行起来以后,输入除了Ctrl c
之外的其他命令是没法运行的,这是因为这个程序是前台进程
,系统在一个终端中只允许有一个前台进程。因此,当这个程序在前台运行起来以后,bash
也是一个进程,此时其处在后台的,所以接收不到我们发送的其他命令。
但是Ctrl c
指令是通过硬件的输入方式中断进程,它的本质也是通过系统向进程发送信号。
所以如果把这个程序放在后台运行,Ctrl c
指令就无法终止整个程序。此时bash
处在前台,可以接收到我们输入的其他命令。
当进程被设置为后台进程时,我们在命令行输入的消息流会和后台进程的信息混合在一起,这是因为bash
进程是在前台的,我们可以输入信息,但是显示器只有一个,被两个进程同时使用,说明他是临界资源,而这个临界资源又没有被保护,因此它的数据会发生混乱。
此时输入fg 进程路径
就可以让进程从后台回到前台。
1.1.1.用signal系统调用接口验证ctrl c是信号
这个接口能够捕捉并重定向一个信号的默认处理动作,使信号不执行原来的动作,而是执行我们自定义的动作
#include <signal.h>
typedef void (\*sighandler\_t)(int);
sighandler\_t signal(int signum, sighandler\_t handler);
signum:对应信号的编号(普通信号编号1-31,实时信号编号34-64)
handler:回调函数(函数指针),传一个函数的地址。这个函数就是我们自定义的处理动作。
ctrl c
发送的是2号信号:
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void handler(int signo){
printf("catch a signal:%d\n",signo);
}
int main(){
while(1){
signal(2,handler);//收到2号信号就执行我们设定的动作
printf("I am running..!\n");
sleep(1);
}
}
由于我们修改了其默认处理动作,所以输入Ctrl c
是不会退出的,而是执行我们设定好的动作。
此时可以使用Ctrl \
来退出,这个指令是发送的是3号信号SIGQUIT
SIGSTOP和SIGKILL不可捕获
9号信号SIGKILL和19号信号 SIGSTOP是不能被signal函数捕捉并修改默认动作的。原因也很简单:如果所有信号都可以被捕捉,病毒可以将所有信号捕捉更改掉,系统就瘫痪了,因此需要这俩信号不能被捕捉,即系统始终拥有对进程的终止能力。
1.1.2.小结
- Shell可以同时运行一个前台进程和任意多个后台进程,只有前台进程才能接到像 Ctrl-C 这种控制键产生的信号。
Ctrl c
产生的信号只能发给前台进程。一个命令后面加个&可以放到后台运行,这样Shell不必等待进程结束就可以接受新的命令,启动新的进程。- 前台进程在运行过程中用户随时可能按下
Ctrl c
而产生一个信号,也就是说该进程的用户空间代码执行到任何地方都有可能收到SIGINT
信号而终止,所以信号相对于进程的控制流程来说是异步的。
二、信号的常见处理方式
当进程收到信号以后,可选的处理动作有以下三种:
- 忽略此信号。
- 执行该信号的默认处理动作。
- 提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数,这种方式称为捕捉(Catch)一个信号。
信号产生之后,不是立即被处理的:
信号从产生到处理的过程中是有时间窗口的,在这个时间窗口之内信号是要排队的,所谓的排队是将这个信号记录或保存下来。
三、信号的产生
3.1.通过终端按键产生信号
信号的第一种产生方式是通过键盘,常见的有以下几种:
- ctrl+c 2号信号 SIGINT
- ctrl+z 20号信号 SIGTSTP
- ctrl+\ 3号信号 SIGQUIT
3.2.通过调用系统函数向进程发信号
3.2.1.kill
这个系统调用函数可以给指定的进程发送信号。
#include <sys/types.h>
#include <signal.h>
int kill(pid\_t pid, int sig);
pid:代表目标进程的pid
sig:代