【Linux】任务管理,作业控制与守护进程

请添加图片描述

任务管理

在运行进程的时候后面加上&,表示让这个进程放在后台运行。
每一个进程都是一个任务,都有一个作业号

使用jobs命令可以查看所有的任务和其作业号

使用fg 作业号可以让后台进程放到前台运行

后台运行的进程的状态是R,而前台运行的进程状态是R+

bash中只允许存在一个前台进程,而bash也是一个进程,所以当前台已经有一个进程在运行的时候,bash就不能解析命令了,所以此时尝试运行命令是没有用的。

使用ctrl + z组合将可以让进程以暂停的状态运行在后台

使用bg 作业号,可以将后台进程运行起来

使用终端登录Linux,本质都是先创建一个bash进程,整体称之为一个会话session,所有的命令行启动的任务都是在对应session中运行的

使用ps -o pid,ppid,pgrp,session,tpgid,command查看当前会话的进程号,进程组号,会话号,终端进程组号,进程名称

进程组

每个进程除了有一个进程ID之外,还属于一个进程组。进程组是一个或多个进程的集合。通常,它们与同一个作业相关联,可以接收来自同一个终端的各种信号。

命令行上启动的多个进程,协同完成某项任务,其中第一个被创建出来的进程,称之为组长进程。组长进程的进程号和进程组号是相同的。

作业

shell分前后台控制的不是进程,而是作业或者进程组。一个前台作业可以由多个进程组成,一个后台也可以由多个进程组成,shell可以运行一个前台作业和多个后台作业。

会话

会话是一个或多个进程组的集合。
一个会话可以有一个控制终端。建立与控制终端连接的会话首进程被称为“控制进程”。一个会话中应该包括控制进程,一个前台进程组合多个后台进程组。

守护进程

当一个会话关闭之后,其中所有的进程会变成孤儿进程。为了在会话关闭之后,还可以是一个进程持久地服务下去,就需要使用到守护进程

守护进程也称为“精灵进程”,是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。Linux的大多数服务器就是用守护进程实现的。

Linux系统启动时会启动很多系统服务进程,这些系统服务进程没有控制终端,不能直接和用户交互。其他进程都是在用户登录或运行程序时创建,在运行结束或用户注销终止,但系统服务进程不受用户登录注销的影响,一直运行。这些进程就是守护进程。

TPGID为-1的进程就是没有控制终端的进程也就是守护进程,在COMMAND一列用[]括起来的表示该进程为内核线程。

系统调用接口daemon

#include <unistd.h>
int daemon(int nochdir, int noclose);
  • 作用
    • 使得当前进程变成守护进程
  • 参数
    • nochdir:是否需要更改守护进程的工作目录为根目录,默认是更改
    • noclose:是否需要关闭守护进程中的文件描述符

模拟实现daemon进程

实现守护进程的核心步骤就是让一个非进程组组长进程创建出一个新的会话,由于当前会话不能干预新创建出的会话,所以当前进程就可以一直运行下去了。

  1. 调用umask将文件屏蔽字设置为0
  2. 调用fork,父进程退出。
  • 原因
    • 如果父进程是shell命令启动的,那么父进程退出shell认为命令已经执行完毕,此时只剩下一个子进程,该子进程不是进程组的组长,满足使用setsid的条件。
  1. 忽略SIGCHLD信号
  2. (核心步骤)使用setsid创建一个新的会话
  • 原因
    • 使用setsid可以创建出一个新的会话,使当前进程成为会话首进程,同时也是进程组的组长。但是使用setsid的前提是当前进程不能是组长进程,而为了不成为组长进程,需要fork出一个子进程,子进程可以调用setsid
  1. fork一次,父进程退出
  • 原因
    • 只有会话首进程才能打开一个终端,因为守护进程不需要再打开终端了,所以可以再fork一次,让父进程退出,如此子进程就不是会话首进程,也就不能打开终端了
  1. 将当前工作目录更改为根目录
  • 原因
    • 将当前工作目录设置为根目录,这样守护进程必须要使用绝对路径的方式访问文件。可以使用ls /proc/[pid] -al命令查看进程当前工作目录
  1. 关闭不需要的文件描述符或者将3个标准文件重定向到/dev/null
  • 原因
    • 让进程和IO设备取消关联,如果将文件重定向到/dev/null代表将输入到源文件的文件全丢弃
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>

void my_daemon(int nochdir, int noclose)
{
	umask(0);
	if (fork() > 0)
	{
		exit(0);
	}
	signal(SIGCHLD, SIG_IGN);
	
	setsid();

	if (fork() > 0)
	{
		exit(0);
	}
	
	chdir("/");
	
	int fd = open("/dev/null", O_RDONLY);
	dup2(fd, 0);
	dup2(fd, 1);
	dup2(fd, 2);	
}

int main()
{
	my_daemon(0, 0);
	return 0;
}
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hyzhang_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值