Linux任务管理与守护进程
- Linux任务管理与守护进程详解
- 任务管理
- 进程组概念
- 作业概念
- 会话概念
- 相关操作
- 前台进程&后台进程
- jobs、fg、bg
- ps命令查看指定的选项
- 守护进程
- 守护进程的概念
- 守护进程的查看
- 守护进程的创建
- 原生创建守护进程
- 调用daemon函数创建守护进程
- 模拟实现daemon函数
- 总结
Linux任务管理与守护进程详解
任务管理
进程组概念
在Linux中,每个进程不仅有进程ID(PID),还属于一个进程组。进程组是一个或多个进程的集合,通常与同一作业相关联,可接收同一终端的信号。
- 进程组ID(PGID):每个进程组有唯一标识。
- 组长进程:其PGID等于PID,可创建组内进程并终止。
- 存在性:只要组内有一个进程存在,进程组就存在,与组长进程是否终止无关。
作业概念
Shell通过**作业(Job)或进程组(Process Group)**管理前后台任务,而非直接控制单个进程。
- 作业组成:一个作业可包含多个进程。
- 作业控制:Shell支持一个前台作业和多个后台作业。
- 作业与进程组的区别:若作业中的进程创建子进程,该子进程不属于作业。作业结束后,若子进程仍存在,会自动变为后台进程组。
会话概念
**会话(Session)**是一个或多个进程组的集合,通常与一个控制终端关联(如终端设备或伪终端)。
- 控制进程:会话首进程与终端建立连接。
- 进程组划分:会话包含一个前台进程组和多个后台进程组。
- 示例:运行5个死循环程序:
mytest1 & mytest2 &
:后台进程组。mytest3 | mytest4 | mytest5
:前台进程组。- Shell单独成组,共享同一会话和控制终端。
- 信号传递:终端输入(如
Ctrl+C
生成SIGINT
)只发送给前台进程组。
相关操作
前台进程&后台进程
- 前台运行:
./program
,状态为R+
(带+
表示前台)。 - 后台运行:
./program &
,状态为R
,输出类似[1] 16437
,其中[1]
是作业编号,16437
是进程ID。 - 多进程示例:启动4个后台进程,分别标记为1-4号作业。
jobs、fg、bg
jobs
:查看当前会话的作业列表。fg
:将作业提到前台。- 示例:
fg 1
,将1号作业提至前台,状态变为R+
。 - 注意:前台只能有一个进程,bash会自动变为后台。
- 示例:
bg
:让停止的作业在后台继续运行。- 示例:
Ctrl+Z
停止前台进程(状态变为T
),bg 1
恢复运行(状态为R
)。 - 本质:发送
SIGCONT
信号。
- 示例:
ps命令查看指定的选项
ps -o
:自定义输出字段,查看当前会话进程信息。- 会话关系:登录创建bash进程,形成一个会话,所有命令行任务共享同一会话ID(SESS)。
- 系统级查看:
ps axj
,显示所有进程。
守护进程
守护进程的概念
**守护进程(Daemon)**是一种运行在后台的特殊进程,独立于控制终端,周期性执行任务或等待事件。
- 特点:无控制终端,不受用户登录注销影响。
- 实例:
inetd
(Internet服务器)、httpd
(Web服务器)、crond
(作业调度)。 - 命名:通常以
d
结尾,如syslogd
。
守护进程的查看
使用 ps axj
查看:
- 参数:
a
:列出所有用户进程。x
:包括无终端进程。j
:显示作业控制信息。
- 标识:TPGID为
-1
表示无控制终端,即守护进程。 - 内核线程:COMMAND以
[ ]
括起来,通常以k
开头(如[kthreadd]
)。
常见守护进程:
udevd
:管理/dev
设备文件。acpid
:电源管理。syslogd
:日志维护。
守护进程的创建
原生创建守护进程
创建步骤:
- 设置文件掩码:
umask(0)
,确保文件权限符合预期。 - 创建新会话:
fork()
后父进程退出,子进程调用setsid()
与终端脱离。 - 忽略SIGCHLD:
signal(SIGCHLD, SIG_IGN)
,避免僵尸进程。 - 再次fork(可选):确保子进程不是会话首进程,防止重新关联终端。
- 更改目录(可选):
chdir("/")
,便于绝对路径访问资源。 - 重定向IO(可选):将标准输入/输出/错误重定向至
/dev/null
。
代码示例:
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
int main() {umask(0);if (fork() > 0) exit(0);setsid();signal(SIGCHLD, SIG_IGN);if (fork() > 0) exit(0);chdir("/");close(0);int fd = open("/dev/null", O_RDWR);dup2(fd, 1);dup2(fd, 2);while (1);return 0;
}
验证:
ps axj
:TPGID为-1
,TTY为?
。- PID ≠ PGID ≠ SID,非组长且独立会话。
/proc/<pid>
:工作目录为/
,IO重定向至/dev/null
。
调用daemon函数创建守护进程
int daemon(int nochdir, int noclose);
- 参数:
nochdir
:0时更改目录为/
。noclose
:0时重定向IO至/dev/null
。
- 示例:
#include <unistd.h>
int main() {daemon(0, 0);while (1);return 0;
}
特点:创建的守护进程是会话首进程(SID=PID),未防止终端关联。
模拟实现daemon函数
自定义实现:
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
void my_daemon(int nochdir, int noclose) {umask(0);if (fork() > 0) exit(0);setsid();signal(SIGCHLD, SIG_IGN);if (fork() > 0) exit(0);if (!nochdir) chdir("/");if (!noclose) {close(0);int fd = open("/dev/null", O_RDWR);dup2(fd, 1);dup2(fd, 2);}
}
int main() {my_daemon(0, 0);while (1);return 0;
}
优势:比系统 daemon
多一步 fork
,更彻底脱离终端。
总结
- 任务管理:通过进程组、作业和会话实现前后台控制,
jobs
、fg
、bg
等命令提供灵活操作。 - 守护进程:后台运行的特殊进程,创建需脱离终端,可通过原生步骤或
daemon
函数实现。