进程间的关系及守护进程

时间:2021-09-03 04:21:30

1.进程组


1.1 定义


1.进程组是一个或多个进程的集合,可接受来自同一终端的信号。
2.每个进程组有唯一的进程组ID。
3.每个进程有一个组长进程,组长进程标识是:进程组ID等于进程ID,组长进程可以创建一个进程组.
4.只要在某个进程组中一个进程存在,则该进程组就存在,这与其组长进程是否终止无关。<a

1.2演示


进程间的关系及守护进程

创建三个后台进程,sleep 1000 ,sleep 2000,sleep 3000
& :表示将进程放在后台执行
fg 进程号 //将进城提至前台
jobs :查看当前有哪些作业
bg 进程号 :唤醒后台进程
ps axj : a :不仅列出当前用户的进程,也列出所有其他用户的进程
         x:不仅列出有控制终端的进程,也列出所有无控制终端的进程
         j:列出与作业控制相关的信息

2.作业


2.1 定义


shell分前后台控制的是作业而非进程
一个前台作业可以由多个进程组成,一个后台作业也可以有多个进程组成。
作业控制:shell可以运行一个前台作业多个后台作业.

作业与进程组的区别:

如果作业中的某个进程又创建了子进程,则子进程不属于作业。
当作业运行结束时,shell将自己提到前台,如果原来的前台进程还在,自动变为后台进程组。

2.2 实例


  1 #include <stdio.h>
  2 #include <unistd.h>
  3 
  4 int main()
  5 {
  6     pid_t id=fork();
  7     if(id<0)
  8     {   
  9         perror("fork error");
 10         return 1;
 11     }
 12     else if(id==0)
 13     {
 14         while(1)
 15         {
 16             printf("child(%d)# I am running!\n",getpid());
 17             sleep(1);
 18 
 19         }
 20 
 21     }

 23     else //父进程
 24     {
 25         int i=4;
 26         while(i)
 27         {
 28             printf("parent(%d) #I am going to dead...%d\n",getpid(),i--);
 29             sleep(1);
 30         }
 31     }
 32 
 33     return 0;

运行结果:
进程间的关系及守护进程

运行代码发现,在父进程运行完毕后,子进程还在运行,输入ls等命令可以执行,说明此时shell被提到了前台,即子进程自动变为后台进程

3.会话


3.1 定义


会话是一个或多个进程组的集合。一个会话可以有一个控制终端
控制进程:建立与控制终端相连接的会话首进程
一个会话中包括控制进程(会话首进程),一个前台进程组和任意后台进程组。

3.2实例


进程间的关系及守护进程

在结果中可以看到,三个进程属于同一进程组,同一会话,具有同一父进程7985 ,通过命令查看。7985为 -bash

4.守护进程


4.1定义


1.守护进程又称为精灵进程(daemon),是运行在后台的一种特殊进程
2.它独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件
3.linux大多服务器由守护进程实现:ssh、web、httpd等
系统服务进程(守护进程)不受用户登录注销的影响,一直运行,无控制终端,不能和用户直接交互

4.2 实例


进程间的关系及守护进程

通过ps zxj | more 查看系统中的进程
a.TPGID为-1的是无控制终端的进程,即守护进程
b.在COMMAND 用[]括起来的是内核线程,即在内核中创建,无用户空间代码,因此没有程序文件名和命令行,通常用k开头的名字。
守护进程通常以d结尾的名字,daemon

4.3 创建守护进程


调用setsid函数创建一个新的会话,并成为会话首进程

#include <unistd.h>
pid_t setsid(void);
//成功返回创建的会话id,出错返回-1.

注意:调用该函数前,当前进程不允许是进程组的组长,否则返回-1.。即先fork在调用setsid。总结为守护进程自成进程组,自成会话
如果当前进程原本有一个控制终端,则它将失去这个控制终端,成为一个无控制终端的进程,即原来的控制终端仍然是打开的,可以读写,但只是一个普通而文件而非控制终端.


编写过程:a.调用umask将文件模式创建屏蔽字设置为0
        b.调用fork,父进程退出(exit)
        c.调用setsid创建新回话
        d.忽略SIGCHLD信号
        e.将当前目录更改到根目录
        f.关闭不需要的文件描述符或重定向到/dev/null

void mydaemon()
{
    umask(0);
    pid_t id = fork();
    if(id > 0 )
    {
        exit(1);
    }

    printf("Debug\n");
    setsid(); //创建新会话

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

    close(0); //关闭文件描述符
    close(1);
    close(2);

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

}

int main()
{
    mydaemon();
    while(1); //死循环,方便我们查看
    return 0;
}

结果为:
进程间的关系及守护进程

进程间的关系及守护进程

也可使用库函数
#include <unistd.h>

int daemon(int nochdir, int noclose);
第一个参数nochdir如果设置为0的话表示将工作目录改为根目录。第二个参数noclose如果设置为0的话就将文件描述符重定向到/dev/null文件。与上面原理相似。 
#include<stdio.h>
#include<unistd.h>

int main()
{
     daemon(0,0);
     while(1);//死循环为了方便查看
     return 0;
}