linux-进程信号的产生与发送
预备知识
在日常生活中常见信号比如:信号弹,上课铃声,红绿灯等等... ...
首先进程需要认识这些信号。
1,能够识别信号。
2,知道信号的处理方法。其次即便我们现在没有接收到信号,我们也要知道信号产生后我们该干什么。
之后信号产生了,我们可能并不会处理这个信号,在合适的时候,我们有着更重要的事,信号产生后,会暂时在时间窗口进行标记,及进程记录信号的到来。
对于进程而言
1.进程必须能够识别和处理悉信号--信号没有产生,也要具备信号处理的能力。
2.进程即便没有收到信号,也要知道哪些信号该处理。
3.当进程真的收到了一个具体的信号的时候,进程可能并不会立即处理,待合适的时候再处理。
信号的处理方式:
1.默认动作
2.忽略
3.自定义动作(信号的捕捉)
4.一个进程必须当信号产生,到信号开始被处理,就一定会有时间窗口,进程具有临时保存哪些信号已经发生了的能力。
ctrl+c为什么能够杀死前台进程?
原因在于键盘输入首先是被前台进程收到的,快捷键本质是被解释为2号信号
在Linux中,一个终端,一般会有一个bash,每一个登陆,只允许一个进程是前台进程,可以允许多个进程是后台进程
验证
signal接口
在Linux中,signal(信号) 是进程间传递异步通知的一种机制,用于处理突发事件(如用户中断、程序错误等)。
信号的基本概念
- 信号是内核向进程发送的简短消息,告知进程发生了某种事件。
- 进程收到信号后,会中断当前操作,转而去执行预设的信号处理函数(默认行为或自定义函数)。
常见信号及默认行为
Linux中有60多种信号(可通过 kill -l 查看),部分常用信号如下:
- SIGINT(2):用户按下 Ctrl+C 发送,默认终止进程。
- SIGTERM(15):默认的终止信号,进程可捕获并清理资源后退出。
- SIGKILL(9):强制终止信号,进程无法捕获或忽略,用于强制结束进程。
- SIGSEGV(11):段错误信号,进程访问无效内存地址时触发,默认终止并生成核心转储。
- SIGSTOP(19):暂停进程信号,无法被忽略或捕获,需用 SIGCONT 恢复。
信号的处理方式
进程收到信号后,有3种处理方式:
1. 默认行为:系统预设的处理(如终止、暂停、忽略等)。
2. 忽略信号:进程不做任何处理( SIGKILL 和 SIGSTOP 无法忽略)。
3. 自定义处理:通过 signal() 或 sigaction() 注册函数,信号触发时执行自定义逻辑。
常用信号操作命令
- kill -信号编号 进程ID :向指定进程发送信号(如 kill -9 1234 强制终止PID为1234的进程)。
- pkill -信号 进程名 :向指定名称的进程发送信号(如 pkill -INT nginx 终止nginx进程)。
- trap '命令' 信号 :在shell脚本中捕获信号并执行命令(如 trap 'echo "收到中断"' INT )。
信号机制是Linux进程通信的重要组成部分,常用于进程控制、异常处理等场景。
现象:
不改变2号信号默认行为。ctrl+c可以直接中断进程
改变2号信号默认行为。ctrl+c不可以中断进程
得证ctrl+c==2号信号
---------------------------------------------------------------------------------------------------------------------------------
键盘数据传输给内核的方式,及快捷键转换成信号的方式:
内容传输过程
信号的产生方式
1.键盘组合键
2.kill命令 (kill -signo pid)
3.系统调用
在Linux中, kill 、 raise 、 abort 都是与进程信号相关的函数或命令,用于发送信号给进程以控制其行为(如终止、暂停等)。以下是它们的核心区别和用法:
1. kill(系统调用/命令)
- 作用:向指定进程发送信号(默认发送终止信号 SIGTERM )。
- 使用场景:
- 作为命令行工具:用于手动向进程发送信号,格式为 kill [信号] 进程ID 。例如 kill -9 1234 发送强制终止信号 SIGKILL 给进程1234。
- 作为系统调用:在程序中通过 kill(pid, sig) 函数向指定 pid 的进程发送信号 sig 。
- 特点:可以向任意进程发送信号(需权限),不仅限于自身。
2. raise(库函数)
- 作用:向当前进程(调用 raise 的进程)发送指定信号。
- 函数原型: int raise(int sig);
- 特点:
- 等价于 kill(getpid(), sig) ,只能向自身进程发送信号。
- 常用于进程内部主动触发信号(如自我终止、调试等)。
3. abort(库函数)
- 作用:强制当前进程异常终止,生成核心转储文件(core dump),用于调试。
- 函数原型: void abort(void);
- 特点:
- 本质是向自身发送 SIGABRT 信号(默认处理方式为终止进程并生成core文件)。
- 无法被进程捕获或忽略(即使注册了信号处理函数,最终仍会终止),确保进程退出。
- 常用于程序遇到致命错误时的“自我终结”(如断言失败后的处理)。
总结
- kill :通用信号发送工具,可跨进程。
- raise :仅向自身进程发送信号,简化版 kill 。
- abort :专用自我终止函数,强制异常退出并生成调试信息。
4.异常(除零错误,野指针,访问越界等)
Cpu也是硬件,同时操作系统是硬件的管理者,因此异常会给进程发送信号,操作系统会随时访问进程的上下文,一旦有异常,操作系统会立刻得知,因为错误局限于进程内部,因此它不会干扰操作系统的正常运行
5.软件条件
软件条件产生信号是指在程序运行过程中,由软件自身的特定行为或状态触发的信号,而非硬件(如键盘中断、硬件错误)触发。这些信号通常用于处理程序内部的异常或特定逻辑。
常见的软件条件产生信号包括:
- SIGFPE:因算术错误(如除零、浮点溢出)触发。
- SIGSEGV:访问非法内存地址(如越界访问、空指针解引用)时产生。
- SIGABRT:调用 abort() 函数时触发,用于程序主动报告致命错误。
- SIGPIPE:向已关闭的管道或套接字写入数据时产生。
- SIGINT:虽常由键盘 Ctrl+C 触发,但程序也可通过 kill 等函数主动发送,用于请求进程终止。
这些信号由操作系统根据软件运行状态自动生成,进程可通过注册信号处理函数来捕获并处理,以实现错误恢复或优雅退出。
闹钟alarm
在Linux中, alarm 是一个系统调用,用于设置一个定时器,当定时器到期时,会向当前进程发送 SIGALRM 信号(默认处理方式为终止进程)。
主要作用
- 让进程在指定秒数后收到 SIGALRM 信号,用于实现定时触发操作(如超时控制、定时任务等)。
函数原型
unsigned int alarm(unsigned int seconds);
- 参数 seconds :定时秒数,若为0则取消之前设置的定时器。
- 返回值:若之前已设置定时器,返回剩余秒数;否则返回0。
特点
- 定时器为一次性的,触发后自动失效,若需重复定时需重新调用。
- 同一进程中,新设置的 alarm 会覆盖之前的定时器。
- 通常需要配合信号处理函数(捕获 SIGALRM )来实现自定义逻辑(如执行特定任务而非终止进程)。
例如,程序中调用 alarm(5) ,5秒后会收到 SIGALRM ,若未自定义处理,进程会终止;若注册了处理函数,则可在函数中执行超时后的操作。
信号退出类型
在Linux信号处理中, term 和 core 是信号默认处理方式的两种常见类型,用于描述进程退出的行为:
- term(终止):指信号触发后,进程会被正常终止,释放资源,但不会生成核心转储文件(core dump)。
例如 SIGTERM (默认终止信号)、 SIGINT (Ctrl+C触发)等,通常用于正常结束进程。
- core(终止并生成核心转储):指信号触发后,进程不仅会被终止,还会生成一个包含进程内存状态的 core 文件,用于调试(分析崩溃原因)。
例如 SIGSEGV (非法内存访问)、 SIGABRT (调用 abort() 触发)等,这类信号通常对应程序异常错误。
简单说, term 是“干净退出”, core 是“异常退出并留调试信息”。
核心转储在云服务器上是默认关闭的,打开方式如下
在Linux中, ulimit 用于控制进程的资源限制,其中 -a 和 -c 是常用选项:
ulimit -a
- 作用:显示当前进程所有资源限制的默认值,包括文件大小、核心文件大小、打开文件数等。
- 输出内容:会列出各类限制项及其当前值,例如:
- core file size (核心文件大小限制)
- file size (文件大小限制)
- open files (最大打开文件数)等。
- 用途:快速查看系统对进程的资源限制配置。
ulimit -c
- 作用:专门控制核心转储文件(core dump)的大小限制。
- 默认值通常为 0 ,表示禁止生成核心文件。
- 若设置为具体数值(如 ulimit -c 1024 ),则限制核心文件最大为1024块(单位依系统而定)。
- 设置为 unlimited ( ulimit -c unlimited ),表示允许生成任意大小的核心文件。
- 用途:调试程序时,需开启此限制以生成核心文件(如 SIGSEGV 等信号触发时),方便分析崩溃原因。
总结: ulimit -a 是资源限制的“总览”, ulimit -c 是专门控制核心文件生成的开关和大小。
为什么云服务器上核心转储是关闭的呢?
云服务器中核心转储(core dump)默认关闭,主要出于以下几方面考虑:
- 节省存储空间:核心转储文件会包含进程崩溃时的完整内存数据,体积可能很大(甚至达数GB)。云服务器通常需要高效利用存储资源,默认关闭可避免大量冗余文件占用空间,尤其对多用户共享的云环境更重要。
- 安全性:核心文件可能包含敏感信息,如密码、密钥、用户数据等。默认关闭可减少敏感数据泄露的风险,尤其在公共云或多租户环境中。
- 性能与稳定性:生成核心文件时,进程需要将大量内存数据写入磁盘,可能占用I/O资源并影响服务器响应速度。默认关闭可避免这种额外开销,保障云服务器的基础性能。
信号的发送
信号实际上是发送给进程的pcb,进程通过位图来管理信号,所谓的发信号,实际上是操作系统修改进程中task_struct对应位图的二进制码,只有操作系统有资格去修改进程的属性,因为操作系统是进程的管理者
比特位是0或者1,表示是否收到信号?
比特位的位置表示信号的编号
信号分为普通信号和实时信号
普通信号:同时并发性发送多个普通信号时,只会处理最近的一个普通信号
实时信号:但是如果同时并发性发送多个实时信号操作系统会依次处理实时信号