Linux信号

信号

信号就是Linux中产生的某个事件,接收到信号的进程会采取相应的行动,信号由shell和终端处理器产生来引起中断,还可以作为进程传递消息和修改默认行为的一种方式。简单的,可以理解成Linux系统与进程的一种“交互”方式,像在终端中按下的Ctrl+C、Ctrl+Z组合键所产生的都是属于信号。

这些指令实际上就是给进程传一个相应的信号,然后进程根据接收到的信号产生相应的反应。

这样的理解可能比较抽象

我们可以在Linux中编写程序在执行中就可以理解其中的含义

在编写程序之前我们首先了解关于信号中最重要的函数 signal

这个函数在信号的学习中有着举足轻重的作用

实际上关于这个函数最重要的是关于它的宏

例如这里的SIG_IGN,SIG_DFL都是宏定义

它可以修改进程收到某个指令的应对方式

例如我们这里编写一个每隔一秒打印一个 1 的死循环

我们要如何结束他呢

这里是有两种方式的

我们编译运行

这个程序运行后会不断的输出1

那么我们第一种方式结束就是使用 ctrl +c

强制结束当前进程

 

可以看到这样就结束了这个进程

那么我们第二种方法就是使用之前学习的方法

开启另外一个终端

通过进程号杀死这个程序 

可以看到ps和 ps -f是只能查询到当前终端中的进程

如果想查询到另外一个终端的进程信息,我们可以使用ps -ef加上管道过滤 就可以得到进程信息 

 

 

可以看到这样我们就通过另外一个终端终止了该进程

我们跳转到signal函数的定义处

参数 signum是 信号

参数 handler 是 响应方式

SIGINT就是我们按下 ctrl+c 对应的信号

SIG_IGN的响应方式是忽略信号

那我们可以看看执行这个程序时再按 ctrl+c还有相应的反应嘛

 

程序编译执行

 

可以看到我们按下 ctrl +c 进程并没有结束,还是在持续的打印 5

那么我们只能通过进程号终止程序

 

 

那么这里我们就可以理解函数 signal的含义

就是和系统进行一个约定

当遇到这个指定的信号 会按照你给定的方式进行处理

我们对响应方式进行一点修改 SIG_DFL的意思是按照系统原有的方式进行处理

也就是不做处理

那么按照我们的理解 ctrl+ c可以结束这个进程

我们编译运行看看结果

可以看到我们又可以正常的关闭这个进程

 我们的响应方式只能是系统给定的宏嘛

实际上不是的,我们还可以将响应方式改变为一个自定义的函数

例如我们约定在每次按下ctrl +c时 就打印num

这个num实际上就是SIGINT返回的值

是 2

那么每当我们给出 ctrl +c信号时 就会打印 2

 

这里看到完成了我们的想法

我们还是使用进程号结束这个进程

 那么我们想要第一次给 ctrl +c的时候打印 2

第二次 给出 ctrl +c 的时候结束进程

我们仍然可以通过改变函数结构 来达到目的

 

可以看到这里就实现了我们目的

mykill 

Linux kill 命令用于删除执行中的程序或工作。

kill 可将指定的信息送至程序。预设的信息为 SIGTERM(15),可将指定程序终止。若仍无法终止该程序,可使用 SIGKILL(9) 信息尝试强制删除程序。程序或工作的编号可利用 ps 指令或 jobs 指令查看。

实际上我们可以自己编译一个自己的kill程序

其核心就是 接收到一个信号的返回值 然后按照这个返回值进行不同的处理

这里的sscnaf就是将argv[]中的char类型的值转化为int

使用 atoi函数也可以进行替换

然后这个函数的使用方法就是  ./mykill +进程号

就可以实现系统的 kill 的基础用法

我们这里可以编译运行一下

我们让之前那个打印  1 的程序在后台运行 这样不影响前台的操作

然后我们用 ps -f获取这个进程的进程号

然后使用mykill杀死进程

这里就可以看到 为什么我们编译 mykill的时候使用的argv的参数是两个

第一个解析为 " ./mykill"

第二个解析为 进程号

我们也可以使用之前的方法 把 mykill移动到 bin路径下 从而让其与系统的 kill更加类似

fork()与信号 

SIGCHLD 就是子进程完成后给父进程传入的信号

 如果fun中没有wait那么这个进程在进程执行完后 子进程就会变成僵尸进程

那么我们运行这个程序

这个是程序下半段

我们运行这个程序 预计会输出三个 child后 输出num然后直至运行结束

并且不会出现僵尸进程问题

 

 

也没有出现僵尸进程问题

 这就是信号目前的使用

此外 还有信号列表 其中包含了大部分的信号问题

SIGINT
程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出,用于通知前台进程组终止进程。

SIGQUIT
和SIGINT类似, 但由QUIT字符(通常是Ctrl-/)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号。

 SIGILL
执行了非法指令. 通常是因为可执行文件本身出现错误, 或者试图执行数据段. 堆栈溢出时也有可能产生这个信号。

 SIGTRAP
由断点指令或其它trap指令产生. 由debugger使用。

 SIGABRT
调用abort函数生成的信号。

 SIGBUS
非法地址, 包括内存地址对齐(alignment)出错。比如访问一个四个字长的整数, 但其地址不是4的倍数。它与SIGSEGV的区别在于后者是由于对合法存储地址的非法访问触发的(如访问不属于自己存储空间或只读存储空间)。

 SIGFPE
在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误。

SIGKILL

来立即结束程序的运行. 本信号不能被阻塞、处理和忽略。如果管理员发现某个进程终止不了,可尝试发送这个信号。

 SIGUSR1
留给用户使用

 SIGSEGV
试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据.

 SIGUSR2
留给用户使用

 SIGPIPE
管道破裂。这个信号通常在进程间通信产生,比如采用FIFO(管道)通信的两个进程,读管道没打开或者意外终止就往管道写,写进程会收到SIGPIPE信号。此外用Socket通信的两个进程,写进程在写Socket的时候,读进程已经终止。

 SIGALRM
时钟定时信号, 计算的是实际的时间或时钟时间. alarm函数使用该信号.

 SIGTERM
程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理。通常用来要求程序自己正常退出,shell命令kill缺省产生这个信号。如果进程终止不了,我们才会尝试SIGKILL。

 SIGCHLD
子进程结束时, 父进程会收到这个信号。

如果父进程没有处理这个信号,也没有等待(wait)子进程,子进程虽然终止,但是还会在内核进程表中占有表项,这时的子进程称为僵尸进程。这种情况我们应该避免(父进程或者忽略SIGCHILD信号,或者捕捉它,或者wait它派生的子进程,或者父进程先终止,这时子进程的终止自动由init进程来接管)。

 SIGCONT
让一个停止(stopped)的进程继续执行. 本信号不能被阻塞. 可以用一个handler来让程序在由stopped状态变为继续执行时完成特定的工作. 例如, 重新显示提示符

SIGSTOP
停止(stopped)进程的执行. 注意它和terminate以及interrupt的区别:该进程还未结束, 只是暂停执行. 本信号不能被阻塞, 处理或忽略.

 SIGTSTP
停止进程的运行, 但该信号可以被处理和忽略. 用户键入SUSP字符时(通常是Ctrl-Z)发出这个信号

 SIGTTIN
当后台作业要从用户终端读数据时, 该作业中的所有进程会收到SIGTTIN信号. 缺省时这些进程会停止执行.

 SIGTTOU
类似于SIGTTIN, 但在写终端(或修改终端模式)时收到.

 SIGURG
有"紧急"数据或out-of-band数据到达socket时产生.

 SIGXCPU
超过CPU时间资源限制. 这个限制可以由getrlimit/setrlimit来读取/改变。

 SIGXFSZ
当进程企图扩大文件以至于超过文件大小资源限制。

 SIGVTALRM
虚拟时钟信号. 类似于SIGALRM, 但是计算的是该进程占用的CPU时间.

 SIGPROF
类似于SIGALRM/SIGVTALRM, 但包括该进程用的CPU时间以及系统调用的时间.

 SIGWINCH
窗口大小改变时发出.

SIGIO
文件描述符准备就绪, 可以开始进行输入/输出操作.

 SIGPWR
Power failure

 SIGSYS
非法的系统调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值