得到进程id_搞懂进程组、会话、控制终端关系,才能明白守护进程干嘛的?

守护进程

概念:

守护进程,也就是通常所说的Daemon进程,是Linux中的后台服务进程。周期性的执行某种任务或等待处理某些发生的事件。

Linux系统有很多守护进程,大多数服务都是用守护进程实现的。比如:像我们的tftp,samba,nfs等相关服务。

UNIX的守护进程一般都命名为*d的形式,如httpd,telnetd等等。

生命周期:

守护进程会长时间运行,常常在系统启动时就开始运行,直到系统关闭时才终止。

守护进程不依赖于终端

从终端开始运行的进程都会依附于这个终端,这个终端称为这些进程的控制终端。当控制终端被关闭时,相应的进程都会被自动关闭。咱们平常写进程时,一个死循环程序,咱们不知道有ctrl+c的时候,怎么关闭它呀,是不是关闭终端呀。也就是说关闭终端的同时也关闭了我们的程序,但是对于守护进程来说,其生命周期守护需要突破这种限制,它从开始运行,直到整个系统关闭才会退出,所以守护进程不能依赖于终端。

查看守护进程

ps axj

a: 显示所有 

x:显示没有控制终端的进程 

j:显示与作业有关的信息(显示的列):会话期ID(SID),进程组ID(PGID),控制终端(TT),终端进程组ID(TRGID)

015ce009f3ee71e776790c499b91d525.png

• 所有的守护进程都是以超级用户启动的(UID为0);

• 没有控制终端(TTY为?);

• 终端进程组ID为-1(TPGID表示终端进程组ID,该值表示与控制终端相关的前台进程组,如果未和任何终端相关,其值为-1;

• 所有的守护进程的父进程:

历史上,Linux 的启动一直采用init进程;下面的命令用来启动服务。

这种方法有两个缺点:
1. 启动时间长。init进程是串行启动,只有前一个进程启动完,才会启动下一个进程。
2. 启动脚本复杂。init进程只是执行启动脚本,不管其他事情。脚本需要自己处理各种情况,
这往往使得脚本变得很长。

Systemd 

就是为了解决这些问题而诞生的。它的设计目标是,为系统的启动和管理提供一套完整的解决方案。

根据 Linux 惯例,字母d是守护进程(daemon)的缩写。Systemd 这个名字的含义,就是它要守护整个系统。

进程组、会话、控制终端

• 进程组

shell里的每个进程都属于一个进程组,创建进程组的目的是用于简化向组内所有进程发送信号的操作,即如果一个信号是发给一个进程组,则这个组内的所有进程都会受到该信号【方便管理】。

• PGID进程组ID

进程组内的所有进程都有相同的PGID,等于该组组长的PID。(进程组组长:进程组中有一个进程担当组长。进程组ID(PGID)等于进程组组长的进程ID。已知一个进程,要得到该进程所属的进程组ID可以调用getpgrp。一个进程可以通过另一个系统调用setpgrp来加入一个已经存在的进程组或者创建一个新的进程组。

如果内核支持_POSIX_JOB_CONTROL(该宏被定义)则内核会为Shell 上的每一条命令行(可能由多个命令通过管道等连接)创建一个进程组。从这点上看,进程组不是进程的概念,而是shell上才有,所以在task_struct里并没有存储进程组id之类的变量。

进程组的生命周期到组中最后一个进程终止或其加入其他进程组(离开本进程组)为止。

会话

一般一个用户登录后新建一个会话,每个会话也有一个ID来标识(SID)。登录后的第一个进程叫做会话领头进程(session leader),通常是一个shell/bash。对于会话领头进程,其PID=SID。

控制终端

一个会话一般会拥有一个控制终端用于执行IO操作。会话的领头进程打开一个终端之后, 该终端就成为该会话的控制终端。与控制终端建立连接的会话领头进程也称为控制进程 (controlling process) 。一个会话只能有一个控制终端。

前台进程组

该进程组中的进程能够向终端设备进行读、写操作的进程组。例如登陆shell(例如bash)通过调用int tcsetpgrp(int fd, pid_t pgrp); 函数设置为某个进程组pgrp关联终端设备fd,该函数执行成功后,该进程组pgrp成为前台进程组。

后台进程组

该进程组中的进程只能够向终端设备写。

终端进程组ID

每个进程还有一个属性,终端进程组ID(TPGID),用来标识一个进程是否处于一个和终端相关的进程组中。前台进程组中的进程的TPGID=PGID,后台进程组的PGID≠TPGID。若该进程和任何终端无关,其值为-1。通过比较他们来判断一个进程是属于前台进程组,还是后台进程组。

进程组、对话期和控制终端关系

b180438584f7199d02193491cc3363a3.png
进程组、对话期和控制终端关系
  1. 每个会话有且只有一个前台进程组,但会有0个或者多个后台进程组。
  2. 产生在控制终端上的输入(Input)和信号(Signal)将发送给会话的前台进程组中的所有进程。对于输出(Output)来说,则是在前台和后台共享的,即前台和后台的打印输出都会显示在屏幕上。
  3. 终端上的连接断开时 (比如网络断开或 Modem 断开), 挂起信号将发送到控制进程(controlling process) 。
  4. 一个用户登录后创建一个会话。一个会话中只存在一个前台进程组,但可以存在多个后台进程组。第一次登陆后第一个创建的进程是shell,也就是会话的领头进程,该领头进程缺省处于一个前台进程组中并打开一个控制终端可以进行数据的读写。当在shell里运行一行命令后(不带&)创建一个新的进程组,命令行中如果有多个命令会创建多个进程,这些进程都处于该新建进程组中,shell将该新建的进程组设置为前台进程组并将自己暂时设置为后台进程组。

举例

  1. 打开第一个终端执行命令:
ping 127.0.0.1 -aq | grep icmp &  // 通过管道将两个命令串接起来ping –q不显示timeout信息,将其设置到后台并running
  1. 在第一个终端继续执行命令,在前台再新建一个进程组。【注意没有&】
ping 127.0.0.1 -aq | grep icmp //在前台再新建一个进程组,
  1. 开启第二个终端并运行
 ps axj | grep pts/0      即过滤只看pts/0里的会话

 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
 2109  2111  2111  2111 pts/0     2538 Ss    1000   0:01 bash
 2111  2503  2503  2111 pts/0     2538 S     1000   0:00 ping 127.0.0.1 -aq
 2111  2504  2503  2111 pts/0     2538 S     1000   0:00 grep --color=auto icmp
 2111  2538  2538  2111 pts/0     2538 S+    1000   0:00 ping 127.0.0.2 -aq
 2111  2539  2538  2111 pts/0     2538 S+    1000   0:00 grep --color=auto timeo

• SID都是2111,说明大家都在一个Session里 

• 有三个进程组PGID 2111,2503和2538。我们可以看到用|连起来的ping和grep是在一个进程组里的。

• 2538这个进程组是一个前台的进程组,因为其PGID==TGPID, 2503这个进程组是一个后台进程组

  1. 在第一个终端中执行Ctrl+C
  2. 在第二个终端里继续ps axj | grep pts/0
 PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
 2109  2111  2111  2111 pts/0     2111 Ss+   1000   0:01 bash
 2111  2503  2503  2111 pts/0     2111 S     1000   0:00 ping 127.0.0.1 -aq
 2111  2504  2503  2111 pts/0     2111 S     1000   0:00 grep --color=auto icmp

• 2538那个前台进程组的所有进程都消失了,说明信号会发给前台进程组的所有进程

 • 2111,即bash所在的那个进程组成为了前台进程组。

守护进程创建流程

守护进程创建流程如下:

1. 创建子进程,父进程退出 
2. 在子进程中创建新会话 
3. 改变当前目录为根目录 
4. 重设文件权限掩码 
5. 关闭文件描述符 

1.创建子进程,父进程退出

由于守护进程是脱离控制终端的,因此,完成第一步后就会在shell终端里造成一程序已经运行完毕的假象。之后的所有后续工作都在子进程中完成,而用户在shell终端里则可以执行其他的命令,从而在形式上做到了与控制终端的脱离。

由于父进程已经先于子进程退出,会造成子进程没有父进程,从而变成一个孤儿进程。在Linux中,每当系统发现一个孤儿进程,就会自动由1号进程收养。原先的子进程就会变成init进程的子进程。

2. 在子进程中创建新会话

setsid()函数的作用。一个进程调用setsid()函数后,会发生如下事件:

• 首先内核会创建一个新的会话,并让该进程成为该会话的leader进程,
• 同时伴随该session的建立,一个新的进程组也会被创建,同时该进程成为该进程组的组长。
• 该进程此时还没有和任何控制终端关联。若需要则要另外调用tcsetpgrp,前面讲前台进程组时介绍过。

调用setsid()有以下3个作用:

• 让进程摆脱原会话的控制。
• 让进程摆脱原进程组的控制。
• 让进程摆脱原控制终端的控制。

那么,在创建守护进程时为什么要调用setsid()函数呢?

读者可以回忆一下创建守护进程的第一步,在那里调用了fork()函数来创建子进程再令父进程退出。由于在调用fork()函数时,子进程全盘复制了父进程的会话期、进程组和控制终端等,虽然父进程退出了,但原先的会话期、进程组和控制终端等并没有改变,因此,还不是真正意义上的独立。而setsid()函数能够使进程完全独立出来,从而脱离所有其他进程和终端的控制。

详细见man 2 setsid。

3.改变当前目录为根目

这一步也是必要的步骤。使用fork()创建的子进程继承了父进程的当前工作目录。

由于在进程运行过程中,当前目录所在的文件系统(如“/mnt/usb”等)是不能卸载的,这对以后的使用会造成诸多的麻烦(如系统由于某种原因要进入单用户模式)。

因此,通常的做法是让“/”作为守护进程的当前工作目录,这样就可以避免上述问题。当然,如有特殊需要,也可以把当前工作目录换成其他的路径,如/tmp。改变工作目录的常见函数是chdir()。

4. 重设文件权限掩码

文件权限掩码是指屏蔽掉文件权限中的对应位。

例如,有一个文件权限掩码是050,它就屏蔽了文件组拥有者的可读与可执行权限。由于使用fork()函数新建的子进程继承了父进程的文件权限掩码,这就给该子进程使用文件带来了诸多的麻烦。

因此,把文件权限掩码设置为0,可以大大增强该守护进程的灵活性。设置文件权限掩码的函数是umask()。在这里,通常的使用方法为umask(0)。即赋予最大的能力。

5. 关闭文件描述符

同文件权限掩码一样,用fork()函数新建的子进程会从父进程那里继承一些已经打开的文件。这些被打开的文件可能永远不会被守护进程读或写,但它们一样消耗系统资源,而且可能导致所在的文件系统无法被卸载。

在上面的第(2)步之后,守护进程已经与所属的控制终端失去了联系,因此,从终端输入的字符不可能达到守护进程,守护进程中用常规方法(如printf())输出的字符也不可能在终端上显示出来。

所以,文件描述符为0、1和2的3个文件(常说的输入、输出和报错这3个文件)已经失去了存在的价值,也应被关闭。

代码实现

/*
 关注一口Linux
*/
#include  
#include  
#include  
#include 
#include 
#include  
#include 
#include 

int main(){
 pid_t pid;
 int i, fd;
 char *buf = "This is a Daemon\n";

 pid = fork();
 if (pid 0) {
  printf("Error fork\n");
  exit(1);
 } 
 
 /* 第一步,父进程退出 */
 if (pid > 0) {
  exit(0); 
 }
 /* 第二步 */
 setsid();
 /* 第三步 */  
 chdir("/");  
 /* 第四步 */
 umask(0);
 /* 第五步 */  
 for(i = 0; i  {
  close(i);
 }
 
 /* 这时创建完守护进程,以下开始正式进入守护进程实际工作
  * 注意:由于此时守护进程完全脱离了控制终端,因此,不能像其他普通进程
  * 一样通过printf或者perror将错误信息输出到控制终端,一种通用的办
  * 法是使用syslog服务,将程序中的出错信息输入到系统日志文件中。
  * 本程序着重演示创建守护进程的步骤,暂不演示syslog。
  */
 while(1) {
  if ((fd = open("/tmp/daemon.log", 
    O_CREAT|O_WRONLY|O_APPEND, 0600)) 0) {
   exit(1);
  }
  write(fd, buf, strlen(buf) + 1);
  close(fd);
  sleep(10);
 }
 
 exit(0);
}

执行结果24fa53b3fdb93f46dc75b9c03d328d7e.png由上图可见:• 守护进程./run 的UID为0;• 没有控制终端(TTY为?);• 终端进程组ID为-1;• 守护进程的父进程为1516,即systemd。4e57987b06d4944c87bb16cf600026cc.png

8a5047b7d4e6b4e3e21cdbf2e742f4c7.png

推荐阅读

【1】100ASK_IMX6ULL arm板子如何显示图片、汉字、划线、背景色【2】到底什么是Cortex、ARMv8、arm架构、ARM指令集、soc?一文帮你梳理基础概念【科普】 必读【3】Linux信号量(2)-POSIX 信号量【4】手把手教Linux驱动8-Linux IO模型【5】C语言中的短路现象【6】C语言操作时间函数,实现定时执行某个任务小程序

本公众号全部原创干货已整理成一个目录,点击「干货即可获得。

后台回复「进群」,即可加入技术交流群,进群福利:免费赠送Linux学习资料

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/527978.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

w7计算机的收藏夹里弄出桌面,Win7电脑桌面的便签怎么弄出来?

原标题:Win7电脑桌面的便签怎么弄出来?可能很多人都不知道,作为常用的一款电脑桌面操作系统,Windows 7上除了有Txt记事本和Office办公文档外,还有便笺小工具呢!这款便笺小工具虽然很不起眼,但是…

native html5 区别,H5与Native优劣对比

即将启动爱奇艺商城(mall.iqiyi.com)移动端的native化。项目开始之前当然要梳理下为什么做native,究竟H5跟native比有什么劣势,而H5又为什么占比那么高并且有“Html5才是未来”的说法呢。下面简单理下对比。H5,即Html5,指第5代HTM…

html制作圆盘时钟,jquery+html5制作超酷的圆盘时钟表

自己封装的一个用HTML5jQuery写的时钟表代码:超酷数码钟表//引用的是在线jquery地址,如果不行请自行下载切换(function($){$.fn.drawClock function(options){var mainId $(this);//设置默认参数var defaultOptions {width: 300px,height: 300px,marg…

调用外部程序处理文件_Python使用内置方法、模块调用外部命令

导读Python内置调用外部命令:os.systemos.popenos.popen2os.popen3os.popen4commands模块subprocess模块在Python3中,将os.popen2、os.popen3、os.popen4、commands等模块方法移除所以不用花精力了解,可以绕过了os.system方法os.system("…

计算机软件类ui工资多少,ui设计师工资一般多少

ui设计师月薪大概多少,UI设计师的收入现处于中等水平,一般月薪5000~7000元,资深设计师的收入可上升至7000~10000元。ui设计师月薪大概多少,ui设计师工资有多少?,不清楚ui设计师工资有多少的伙伴可以看看。U…

大学计算机课第二章内容总结,第四周市政系《大学计算机基础》课程总结

本周大一的新生终于在漫长的等待、报到、军训之后开始了大学课程的学习,在《大学计算机基础》课程的学习中,其实只是需要大学确立一种新的学习思想:计算机是人类智慧的结晶,它给予我们这样一种工具,通过对它的使用&…

在maven项目中打开jsp_零基础在intellij中打开一个项目复制粘贴内容即可运行的java拼图...

我刚学java语言,在学习java简单的拼图游戏时发现网上有些居然要导入调试,而且网上有些说的调试方法不明不白,所以我就分享了我的可直接复制在新项目中的源码,如果要直接要搞好的话就可以用结尾的分享提取链接进行百度网盘获取(该项…

计算机考试报名无法弹出支付界面,教资报名支付页面不弹出怎么办 2021教师资格证报名入口网址...

2021教师资格证报名入口是中小学教师资格考试网站,教师资格证报名时间是1月14-17日,请大家请及时登陆教师资格证报名官网报名以防错过考试。点击进入:2021年教师资格考试报名入口教师资格证报名缴费进不了支付页面的话原因可能有以下几点&…

gcn在图像上的应用_GCN总结 - nxf_rabbit75 - 博客园

一、GCN简介GNN模型主要研究图节点的表示(Graph Embedding),图边结构预测任务和图的分类问题,后两个任务也是基于Graph Embedding展开的。目前论文重点研究网络的可扩展性、动态性、加深网络。谱卷积有理论支持,但有时候会受到拉普拉斯算子的…

mysql源码_MySql轻松入门系列——第一站 从源码角度轻松认识mysql整体框架图

一:背景1. 讲故事最近看各大技术社区,不管是知乎,掘金,博客园,csdn基本上看不到有小伙伴分享sqlserver类的文章,看来在国内大环境下是不怎么流行了,看样子我再写sqlserver是不可能再写了&#x…

测试图片色域软件,显示器色域检测

色域是颜色的一种编码,也是某一个规定的色彩空间或者输出装置呈现出来的一个颜色范围,展示给用户看到的颜色,使用显示器色域检测工具,可以检测到电脑显示器的色域情况,并且提供具体的参数,这款软件对于需要…

计算机专业研究生应该如何规划,【图片】2020考研,老学长教你如何规划!【计算机考研吧】_百度贴吧...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼二、关键一步——院校选择我把各位同学的院校选择阶段分为以上几个阶段,因为考研这一年中,很多人的目标院校并不是固定不变的,而是随着不同阶段而改变的。学长我在大三下学期这一时间段内也多次更…

哈尔滨大学计算机和金融,山东153所大学最新排名,46所公办本科,看看有你喜欢的吗...

作为人口大省的山东,也是我国有名的教育大省,不但经济发达,地理位置优越,教育资源也是比较丰富的,山东省有153所大学,在大学数量上还是比较多的。但是山东省在高端教育上一直被吐槽,全国知名大学…

dubbo protocol port 消费者端_企业级 SpringBoot 与 Dubbo 的并用

点击上方“匠心零度”,选择“设为星标”做积极的人,而不是积极废人作者:SimpleWucnblogs.com/SimpleWu/p/10833555.htmlSpringBoot 和 Dubbo 又能碰撞出什么火花呢?我们来看看企业级 SpringBoot 与 Dubbo 的并用。版本:Springboot…

心理学博士vs计算机博士,零基础跨专业考心理学博士,可以给我一些建议吗?...

5星优质答主关注有用62020-12-19回答了:关于跨专业考心理学博士的问题,我曾经也有探索过,说一些我的经历,希望能给你带来一些些帮助。我知道的跨专业考心理学博士最知名的例子就是岳晓东教授,他的经历你可以参考一下&a…

在react项目中编写css,更好的在react项目中写css代码--emotion

简介:emotion是一个JavaScript库,使用emotion可以用写js的方式写css代码。在react中安装emotion后,可以很方便进行css的封装,复用。使用emotion后,浏览器渲染出来的标签是会加上一个css开头的标识。如下:截…

mysql 5.7 差异备份_MySQL 5.7 新备份工具mysqlpump 使用说明 - 运维小结

之前详细介绍了Mysqldump备份工具使用,下面说下MySQL5.7之后新添加的备份工具mysqlpump。mysqlpump是mysqldump的一个衍生,mysqldump备份功能这里就不多说了,现在看看mysqlpump到底有了哪些提升,详细可以查看官网文档。mysqlpump和…

腾达路由器dns服务器未响应,腾达路由器的设置方法

腾达路由器的设置方法许多刚买了tenda路由器的新手朋友们,还不知道腾达tenda路由器的设置方法,下面将通过图文并茂的方式,为你详细的介绍tenda路由器的具体设置步骤,希望能够帮助到你!步骤一:连接好线路电话线入户的用…

mysql8审计_审计对存储在MySQL 8.0中的分类数据的更改

作者:Mike Frank 译:徐轶韬面临的挑战使用敏感信息时您需要拥有审计日志。通常,此类数据将包含一个分类级别作为行的一部分,定义如何处理、审计等策略。在之前的博客中,我讨论了如何审计分类数据查询。本篇将介绍如何…

mysql订单详情的设计_订单功能模块设计与实现

在商城项目中,之前我们介绍了购物车功能模块的实现,商品加入到购物车之后,就是到购物车结算,然后显示购物车的商品列表,点击去结算,然后到了未提交前的订单列表,点击提交订单后,生成…