Linux任务管理与守护进程_linux的守护进程是死循环吗(1)

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前在阿里

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Linux运维全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上运维知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化的资料的朋友,可以点击这里获取!

需要注意的是,只要在某个进程组中有一个进程存在,则该进程组就存在,这与其组长进程是否终止无关。

作业概念

Shell分前后台来控制的不是进程而是作业(Job)或者进程组(Process Group)。

一个前台作业可以由多个进程组成,一个后台作业也可以由多个进程组成,Shell可以运行一个前台作业和任意多个后台作业,这称为作业控制。

作业与进程组的区别:
如果作业中的某个进程又创建了子进程,则子进程不属于作业。一旦作业运行结束,Shell就把自己提到前台,如果原来的前台进程还存在,也就是这个被创建的子进程还没有终止,那么它将自动变为后台进程组。

会话概念

会话(Session)是一个或多个进程组的集合。

一个会话可以有一个控制终端,这通常是登录到其上的终端设备(在终端登录情况下)或伪终端设备(在网络登录情况下)。建立与控制终端连接的会话首进程被称为控制进程。一个会话中的几个进程组可被分为一个前台进程组以及一个或多个后台进程组。所以一个会话中,应该包括控制进程(会话首进程),一个前台进程组和任意多个后台进程组。

例如,下面我们用同一个死循环代码生成了5个可执行程序。
在这里插入图片描述
我们将mytest1和mytest2放到后台运行,将mytest3、mytest4和mytest5放到前台运行。
在这里插入图片描述
其中mytest1与mytest2属于同一个后台进程组,mytest3、mytest4和mytest5属于同一个前台进程组,而Shell本身属于一个单独的进程组。
在这里插入图片描述
这些进程组的控制终端相同,它们同属于一个会话,当用户在控制终端输入特殊的控制键(如Ctrl+C产生SIGINT,Ctrl+\产生SIGQUIT,Ctrl+Z产生SIGTSTP),内核就会发送相应的信号给前台进程组中的所有进程。
在这里插入图片描述

相关操作

前台进程&后台进程

直接运行某一可执行程序,例如./可执行程序,此时默认将程序放到前台运行,在前台运行的进程的状态后有一个+号,例如R+
在这里插入图片描述
运行可执行程序时在后面加上&,可以指定将程序放到后台运行,例如./可执行程序 &,在后台运行的进程的状态后没有+号。
在这里插入图片描述
我们将程序放到后台运行时会发现多了一行提示信息,例如上述的:

[1] 16437

其中[1]是作业的编号,如果同时运行多个作业可以用这个编号进行区分,16437是该作业中某个进程的id(一个作业可以由多个进程组成)。

我们可以用该可执行程序同时创建四个进程放到后台运行:
在这里插入图片描述
此时我们就可以将它们分别叫做当前终端下的1号作业、2号作业、3号作业和4号作业。

jobs、fg、bg

使用jobs命令,可以查看当前会话当中有哪些作业。
在这里插入图片描述
使用fg命令(foreground),可以将某个作业提至前台运行,如果该作业正在后台运行则直接提至前台运行,如果该作业处于停止状态,则给进程组的每个进程发SIGCONT信号使它继续运行并提至前台。

例如,使用fg 1命令将1号作业提到前台运行。
在这里插入图片描述
由于1号作业被提至前台运行,所以其运行状态也由R变成了R+

需要注意的是,前台进程只能有一个,当一个进程变成前台进程后,bash会自动变为后台进程,此时bash就无法进行命令行解释了。

例如,我们将1号作业提至前台运行后,bash进程的状态后面的+号就没有了,也就意味着bash自动由前台进程变为了后台进程。
在这里插入图片描述
将一个前台进程放到后台运行可以使用Ctrl+Z,但使用Ctrl+Z后该进程就会处于停止状态(Stopped)。
在这里插入图片描述
使用bg命令,可以让某个停止的作业在后台继续运行(Running),本质就是给该作业的进程组的每个进程发SIGCONT信号。

例如,使用bg 1命令让1号作业在后台继续运行。
在这里插入图片描述

ps命令查看指定的选项

使用ps命令时携带-o选项,可以查看指定的信息。
在这里插入图片描述
当我们用Xshell或是终端登录时,本质都是先创建一个bash进程,整体称之为一个会话(所有的命令行的进程都是bash的子进程),所有的命令行启动的任务都是在对应的会话内运行的。

实际我们每一次登录的过程都是新建会话的过程,同一个会话中的所有进程的SESS是相同的。
在这里插入图片描述
说明一下: ps命令是一个系统级的命令,该命令能查看所有进程的信息,例如ps axj,只不过-o选项只查看当前会话的进程信息。

守护进程

守护进程的概念

守护进程也称精灵进程(Daemon),是运行在后台的一种特殊进程,它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。

守护进程是一种很有用的进程,Linux的大多数服务器就是用守护进程实现的,比如Internet服务器inetd,Web服务器httpd等。同时守护进程完成许多系统任务,比如作业规划进程crond等。

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

守护进程的查看

我们可以用ps axj命令查看系统中的进程:

  • 参数a表示不仅列出当前用户的进程,也列出所有其他用户的进程。
  • 参数x表示不仅列出有控制终端的进程,也列出所有无控制终端的进程。
  • 参数j表示列出与作业控制相关的信息。

凡是TPGID一栏写着-1的都是没有控制终端的进程,也就是守护进程。
在这里插入图片描述
除此之外,在COMMAND一列用[ ]括起来的名字表示内核线程,这些线程在内核里创建,没有用户空间代码,因此没有程序文件名和命令行,通常采用以k开头的名字,表示Kernel。

个别说明:

  • udevd负责维护/dev目录下的设备文件。
  • acpid负责电源管理。
  • syslogd负责维护/var/log下的日志文件。

可以看出,守护进程通常采用以d结尾的名字,表示Daemon。

守护进程的创建

原生创建守护进程

守护进程的创建步骤如下:

  1. 设置文件掩码为0。
  2. fork后终止父进程,子进程创建新会话。
  3. 忽略SIGCHLD信号。
  4. 再次fork,终止父进程,保持子进程不是会话首进程,从而保证后续不会再和其他终端相关联。
  5. 更改工作目录为根目录。
  6. 将标准输入、标准输出、标准错误重定向到/dev/null。

相关说明:

  1. 将文件掩码设置为0,保证后续守护进程创建文件时,创建出来的文件的权限符合我们的预期。
  2. 调用setsid创建新会话的目的,是让当前进程自成会话,与当前bash脱离关系(创建守护进程的核心)。
  3. 调用setsid创建新会话时,要求调用进程不能是进程组组长,但是当我们在命令行上启动多个进程协同完成某种任务时,其中第一个被创建出来的进程就是组长进程,因此我们需要fork创建子进程,让子进程调用setsid创建新会话并继续执行后续代码,而父进程我们直接让其退出即可。
  4. 守护进程不能直接和用户交互,也就没有必要再打开某个终端了,而打开一个终端需要你是会话首进程,为了防止守护进程打开终端,我们需要再次fork创建子进程并让子进程继续执行后续代码,由于子进程不是会话首进程,也就没有能力打开其他终端了,而父进程我们直接让其退出即可。(这是一种防御性编程,该操作不是必须的)
  5. 我们一般会将守护进程的工作目录设置为根目录,便于让守护进程以绝对路径的形式访问某种资源。(该操作不是必须的)
  6. 守护进程不能直接和用户交互,也就是说守护进程已经与终端去关联了,因此一般我们会将守护进程的标准输入、标准输出以及标准错误都重定向到/dev/null/dev/null是一个字符文件(设备),通常用于屏蔽/丢弃输入输出信息。(该操作不是必须的)

代码如下:

#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
	//1、设置文件掩码为0
	umask(0);

	//2、fork后终止父进程,子进程创建新会话
	if (fork() > 0){
		//father
		exit(0);
	}
	setsid();

	//3、忽略SIGCHLD信号
	signal(SIGCHLD, SIG_IGN);

	//4、再次fork,终止父进程,保持子进程不是会话首进程,从而保证后续不会再和其他终端相关联
	//(不是必须的,防御性编程)
	if (fork() > 0){
	    //father
		exit(0);
	}

	//5、更改工作目录为根目录(可选的选项)
	chdir("/");

	//6、将标准输入、标准输出、标准错误重定向到/dev/null(可选的选项)
	close(0);
	int fd = open("/dev/null", O_RDWR);
	dup2(fd, 1);
	dup2(fd, 2);
	
	while (1);
	return 0;
}

运行代码,用ps命令查看该进程,会发现该进程的TPGID为-1,TTY显示的是,也就意味着该进程已经与终端去关联了。
其次,我们还可以看到该进程的PID与其PGID和SID是不同的,也就是说该进程既不是组长进程也不是会话首进程。
在这里插入图片描述
此外,我们还可以看到该进程的SID与bash进程的SID是不同的,即它们不属于同一个会话。
在这里插入图片描述
通过ls /proc/进程id -al命令,可以看到该进程的工作目录已经成功改为了根目录。
在这里插入图片描述
通过ls /proc/进程id/fd -al命令,可以看到该进程的标准输入、标准输出以及标准错误也成功重定向到了/dev/null
在这里插入图片描述

调用daemon函数创建守护进程

实际当我们创建守护进程时可以直接调用daemon接口进行创建,daemon函数的函数原型如下:

int daemon(int nochdir, int noclose);

参数说明:

  • 如果参数nochdir为0,则将守护进程的工作目录该为根目录,否则不做处理。
  • 如果参数noclose为0,则将守护进程的标准输入、标准输出以及标准错误重定向到/dev/null,否则不做处理。

调用示例:

#include <unistd.h>

int main()
{
	daemon(0, 0);
	while (1);
	return 0;


### 最后的话

最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!

### 资料预览

给大家整理的视频资料:

![](https://img-blog.csdnimg.cn/img_convert/d788d6c5a785c312ec868fe7b2497f04.png)

给大家整理的电子书资料:

  

![](https://img-blog.csdnimg.cn/img_convert/7424e6dfb0eb5a371312ba8d5ea0b2d6.png)



**如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!**

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618635766)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

外链图片转存中...(img-AYj2TdPS-1715790369930)]



**如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!**

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618635766)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值