进程组、会话、控制终端和守护进程

转载 2016年08月29日 09:42:14

1、进程组

每个进程除了有一个进程ID之外,还有一个进程组。进程组是一个或多个进程的集合。每个进程组都有唯一的进程组ID。函数getpgrp()可以得到进程的进程组ID

1 #include

 2 #include

 3 #include

 4

 5 int main() {

     pid_t pid;

 7

     if ((pid=fork())<0) {

         printf("fork error!");

10     }else if (pid==0) {

11         printf("The child process PID is %d.\n",getpid());

12         printf("The Group ID is %d.\n",getpgrp());

13         printf("The Group ID is %d.\n",getpgid(0));

14         printf("The Group ID is %d.\n",getpgid(getpid()));

15         exit(0);

16     }

17

18     sleep(3);

19     printf("The parent process PID is %d.\n",getpid());

20     printf("The Group ID is %d.\n",getpgrp());

21

22     return 0;

23 }

注:getpgrp()==getpgid(),见1213行。

 

2、会话(此处参考《unix高级编程》)

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

开始于用户登录

终止与用户退出

此期间所有进程都属于这个会话期

进程通过getsid()获得会话id,例:

1 #include

 2 #include

 3 #include

 4

 5 int main() {

     pid_t pid;

 7

     if ((pid=fork())<0) {

         printf("fork error!");

10         exit(1);

11     }else if (pid==0) {

12         printf("The child process PID is %d.\n",getpid());

13         printf("The Group ID of child is %d.\n",getpgid(0));

14         printf("The Session ID of child is %d.\n",getsid(0));

15         sleep(10);

16         setsid(); // 子进程非组长进程,故其成为新会话首进程,且成为组长进程。该进程组id即为会话进程

17         printf("Changed:\n");

18         printf("The child process PID is %d.\n",getpid());

19         printf("The Group ID of child is %d.\n",getpgid(0));

20         printf("The Session ID of child is %d.\n",getsid(0));

21         sleep(20);

22         exit(0);

23     }

24

25     return 0;

26 }

进程调用setsid函数建立新会话。

进程组、会话、控制终端和守护进程

pid_t setsid(void);

该调用进程是组长进程,则出错返回

该调用进程不是组长进程,则创建一个新会话

该进程变成新会话首进程(session header)

该进程成为一个新进程组的组长进程。

该进程没有控制终端,如果之前有,则会被中断

 组长进程不能成为新会话首进程,新会话首进程必定会成为组长进程

在子进程中调用setsid()后,子进程成为新会话首进程,且成为一个组长进程,其进程组id等于会话id

进程可以通过setpgid()来加入已存在的进程组或创建一个新的进程组。例:

1 #include

 2 #include

 3 #include

 4

 5 int main() {

     pid_t pid;

 7

     if ((pid=fork())<0) {

         printf("fork error!");

10         exit(1);

11     }else if (pid==0) {

12         printf("The child process PID is %d.\n",getpid());

13         printf("The Group ID of child is %d.\n",getpgid(0)); // 返回组id

14         sleep(5);

15         printf("The Group ID of child is changed to %d.\n",getpgid(0));

16         exit(0);

17     }

18

19     sleep(1);

20     setpgid(pid,pid); // 改变子进程的组id为子进程本身

21    

22     sleep(5);

23     printf("The parent process PID is %d.\n",getpid());

24     printf("The parent of parent process PID is %d.\n",getppid());

25     printf("The Group ID of parent is %d.\n",getpgid(0));

26     setpgid(getpid(),getppid()); // 改变父进程的组id为父进程的父进程

27     printf("The Group ID of parent is changed to %d.\n",getpgid(0));

28

29     return 0;

30 }

 

3、控制终端

会话和进程组有一些特性:

1). 一个会话可以有一个控制终端(controlling terminal)

2). 建立与控制终端连接的会话首进程被称为控制进程(controlling process)

3). 一个会话中的几个进程组可被分成一个前台进程组(forkground process group)和几个后台进程组(background process group)

4). 如果一个会话有一个控制终端,则它有一个前台进程组。

5). 无论何时键入终端的中断键(DELETECtrl+C),就会将中断信号发送给前台进程组的所有进程。

6). 无论何时键入终端的退出键(Ctrl+\),就会将退出信号发送给前台进程组的所有进程。

7). 如果终端检测到调制解调器(或网络)已经断开连接,则将挂断信号发送给控制进程(会话首进程)

现在,需要有一种方法通知哪个进程组是前台进程组,这样终端设备驱动程序就能了解将终端输入和终端产生的信号送到何处。

 

:这里需要理解何谓前台进程何谓后台进程,前台进程即为可由终端控制的进程,前台进程执行时,终端丧失控制权,前台进程结束后,将控制权交还给终端。后台进程则为独立于终端的进程,例如守护进程即为一个永久性的后台进程。

 

4、守护进程

Linux大多数服务都是通过守护进程实现的,完成许多系统任务

0: 调度进程,称为交换进程(swapper),内核一部分,系统进程

1: init进程, 内核调用,负责内核启动后启动Linux系统

没有终端限制 

让某个进程不因为用户、终端或者其他的变化而受到影响,那么就必须把这个进程变成一个守护进程

进程组、会话、控制终端和守护进程

:但是我个人在参考《linux c编程实战 》一书时,发现其在setsid()之后又加了一步fork()创建子进程exit()使父进程退出,原因是,此时的子进程已经成为会话组的组长,有权利再调出一个终端,如果出现此情况,则未达到完全脱离终端的目的,此时再调用fork并退出父进程,使得此时的子进程成为完全的后台进程,独立于任何的终端。我觉得这点非常重要,也建议大家在尝试创建守护进程时加上这一步。

 

 #include

  #include

  #include

  #include

  #include

  #include

  #include

 

  int main() {

     pid_t pid;

     int i,fd;

     char *buf="This is a daemon program.\n";

 

     if ((pid=fork())<0) {

         printf("fork error!");

         exit(1);

     }else if (pid>0)  // fork且退出父进程

         exit(0);

    

     setsid();    // 在子进程中创建新会话。

    if ((pid=fork())<0) {  //再次调用fork()并退出父进程

         printf("fork error!");

         exit(1);

     }else if (pid>0)  // fork且退出父进程

         exit(0);

     chdir("/");  // 设置工作目录为根

     umask(0);    // 设置权限掩码

     for(i=0;i返回子进程文件描述符表的项数

         close(i);                // 关闭这些不将用到的文件描述符

 

     while(1) {// 死循环表征它将一直运行

 // 以读写方式打开"/tmp/daemon.log",返回的文件描述符赋给fd

         if ((fd=open("/tmp/daemon.log",O_CREAT|O_WRONLY|O_APPEND,0600))<0)   

{

             printf("Open file error!\n");

             exit(1);

         }

         // buf写到fd

         write(fd,buf,strlen(buf)+1);

         close(fd);

         sleep(10);

         printf("Never output!\n");

     }

     return 0;

 }

 

http://blog.sina.com.cn/s/blog_6642cd020101g3tl.html

相关文章推荐

进程组,会话和控制终端

转自:http://shake863.javaeye.com/blog/187085看了《Unix高级环境编程》,不是很清楚这三个概念。看了这篇文章,感觉写得不错,就转载了。将阐述Linux内核中的如...

进程组、会话、控制终端、作业

1、进程组 同一进程组的各个进程接收来自同一终端的各种信号,每个进程由唯一的进程组id,利用getpgrp()或者getpgid(pid)来获取进程组id,每个进程中有一个组长进程,组长进程的id就...

Linux:进程、进程组、会话、作业、控制终端的概念

一、进程  传统上,Unix操作系统下运行的应用程序、 服务器以及其他程序都被称为进程,而Linux也继承了来自unix进程的概念。必须要理解下,程序是指的存储在存储设备上(如磁盘)包含了可执行机器指...

浅谈unix进程,进程组,会话和控制终端的关系

最近看apue进程关系这一章,觉得有必要写一篇博客做个总结 在uni

Linux-进程、进程组、作业、会话、控制终端详解

Linux-进程、进程组、作业、会话、控制终端详解

进程关系之进程组、会话和控制终端

1. 进程组 每个进程除了有一个进程ID之外,还有一个进程组。进程组是一个或多个进程的集合。它们与同一作业相关联,可以接受来自同一终端的各种信号(说出了进程组的作用,即接受来自同一终端的信号)。...

进程的基本属性:进程ID、父进程ID、进程组ID、会话和控制终端

摘要:本文主要介绍进程的基本属性,基本属性包括:进程ID、父进程ID、进程组ID、会话和控制终端. 进程基本属性 1.进程ID(PID) 函数定义: #include #include pi...

进程学习:1-进程、进程组、作业、会话、控制终端详解

一、进程  传统上,Unix操作系统下运行的应用程序、 服务器以及其他程序都被称为进程,而Linux也继承了来自unix进程的概念。必须要理解下,程序是指的存储在存储设备上(如磁盘)包含了可执行机器指...

71-后台进程组与控制终端

本篇需要理清后台进程组与控制终端的关系。我们已经知道,如果会话有一个控制终端,只有前台作业接收终端输入。1. 问题提出如果后台进程组中的进程尝试读写控制终端,会怎么样?这里有两种情况,分别如下: 读控...

进程的基本属性:进程ID、父进程ID、进程组ID、会话和控制终端

摘要:本文主要介绍进程的基本属性,基本属性包括:进程ID、父进程ID、进程组ID、会话和控制终端....
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:进程组、会话、控制终端和守护进程
举报原因:
原因补充:

(最多只允许输入30个字)