操作系统自用6 父子进程管理 创建多个子进程 wait后接信号命令

OS Programme Lecture #6

1. Propagate the signal to multiple children

接着上节课的进程组脚本程序,我们尝试将信号传播给多个子进程

之前,我们使用一个只有一个子进程的脚本。如果一个脚本有很多子进程,并且其中一些还有自己的子进程(进程树形成),会是什么情况?

在第一种情况下,获取所有子作业的 pids 的一种快速方法是使用 jobs -p 命令:

该命令显示当前 shell 中所有活动作业的 pids,我们可以使用 kill 来终止它们。

参考程序:

#!/bin/bash

cleanup() {

echo "cleaning up..."

# Our cleanup code goes here

}

trap 'echo signal received!; kill $(jobs -p); wait; cleanup' SIGINT SIGTERM

echo "The script pid is $"

sleep 30 &

sleep 40 &

wait

该脚本在后台启动两个进程:通过使用不带参数的内置等待,我们等待所有进程,并保持父进程处于活动状态。

当脚本接收到 SIGINT 或 SIGTERM 信号时,我们向它们发送一个 SIGTERM,让它们的 pid 由 jobs -p 命令返回(job 本身是一个内置的 shell,所以当我们使用它时,一个新进程未创建)。

如果子进程有自己的子进程,并且我们想在父进程接收到信号时终止它们,我们可以向整个进程组发送一个信号,就像我们之前看到的那样。

然而,这会带来一个问题,因为通过向进程组发送终止信号,我们将进入“信号发送/信号捕获”循环。

想一想:在 SIGTERM 的陷阱中,我们向进程组的所有成员发送一个 SIGTERM 信号;这包括父脚本本身!

为了解决这个问题并在子进程终止后仍然能够执行清理功能,我们必须在向进程组发送信号之前更改 SIGTERM 的陷阱。

参考程序:

#!/bin/bash

cleanup() {

echo "cleaning up..."

# Our cleanup code goes here

}

trap 'trap " " SIGTERM; kill 0; wait; cleanup' SIGINT SIGTERM

echo "The script pid is $"

sleep 30 &

sleep 40 &

wait

在trap中,在向进程组发送SIGTERM之前,我们改变了SIGTERM trap,让父进程忽略这个信号,只有子进程受到影响。

另外,在陷阱中,为了向进程组发出信号,我们使用 kill 并将 0 作为 pid。

这是一种捷径:当传递给 kill 的 pid 为 0 时,当前进程组中的所有进程都会收到信号。

总结一下:

我们了解了进程组以及前台进程和后台进程之间的区别。

我们学习了 CTRL-C 向控制终端的整个前台进程组发送 SIGINT 信号。

我们学习了如何使用 kill 向进程组发送信号。

我们还学习了如何在后台执行程序,以及如何使用内置的 wait 等待它退出而不丢失父进程。

最后,我们看到了如何设置一个脚本,以便当它接收到一个信号时,它会在退出之前终止它的子进程。

SIGINT

产生方式: 键盘Ctrl+C

产生结果: 只对当前前台进程,和他的所在的进程组的每个进程都发送SIGINT信号,之后这些进程会执行信号处理程序再终止.

SIGTERM

产生方式: 和任何控制字符无关,用kill函数发送

本质: 相当于shell> kill不加-9时 pid.

产生结果: 当前进程会收到信号,而其子进程不会收到.如果当前进程被kill(即收到SIGTERM),则其子进程的父进程将为init,即pid为1的进程.

与SIGKILL的不同: SIGTERM可以被阻塞,忽略,捕获,也就是说可以进行信号处理程序,那么这样就可以让进程很好的终止,允许清理和关闭文件.

SIGKILL

产生方式: 和任何控制字符无关,用kill函数发送

本质: 相当于shell> kill -9 pid.

产生结果: 当前进程收到该信号,注意该信号时无法被捕获的,也就是说进程无法执行信号处理程序,会直接发送默认行为,也就是直接退出.这也就是为何kill -9 pid一定能杀死程序的原因. 故这也造成了进程被结束前无法清理或者关闭资源等行为,这样时不好的.

注意

由于SIGINT, SIGTERM都是可以被捕获的,也就是会执行信号处理函数的,故按照信号处理函数逻辑,可能进程不会退出,即不一定能终止,所以要处理好exit(0).

————————————————

版权声明:本文为CSDN博主「flye422304」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/flye422304/article/details/116890946

####################################################

2. 再来看一个任务,有关Parent and Children Processes

写一个脚本程序 loop_pid_s.sh,可以接收两个参数 ARG1 (进程名,例如PA)、ARG2 (脚本运行时间)。

这个脚本相隔一定时间间隔打印一句话,要用到上面学到的sleep来控制脚本输出。

参考代码:

#!/bin/bash

let time=1

while true; do

echo "$$ I am process $1 - $time-seconds"

sleep $2

let time+=$2

done

完成脚本后,尝试运行传入不同的参数,查看运行结果。尝试用两种方式终止进程。

下面写一个parent.sh脚本程序,参考代码:

#!/bin/bash

(./loop_pid_s.sh PA 10)

(./loop_pid_s.sh PB 10)

echo "Program terminated ..."

运行以上脚本,观察输出。思考:PA和PB两个进程是否并行执行?什么时候最后一个句柄会打印到终端?

现在修改parent.sh脚本程序,参考代码:

#!/bin/bash

(./loop_pid_s.sh PA 10 &)

(./loop_pid_s.sh PB 10 &)

echo "Program terminated ..."

运行以上脚本,比较和之前的输出,思考为什么不一样。

仅供初学者参考学习,除去中间部分已经标明出处的内容外,版权归广大所有

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值