Linux基础概念--进程、子进程、进程组和会话

Linux内核进程,线程,进程组,会话组织模型以及进程管理 唤醒睡眠状态任意的线程可以用wake_up_process,它可唤醒处于深度睡眠状态的线程。结合最开始的图代码,我们可以得到如下结论:1.kthead衍生的内核线程没有session pid,说人话就是所有的内核线程没有都没有操作控制台,不能通过控制台去操作控制。2.idle任务不会出现在for_each_process的处理循环中。3.每cpu_rq就绪队列中,不会将idle统计到nr_running中。 阅读详情

本文基于linux环境编程之守护进程 - 灰信网(软件开发博客聚合)进行实践和完善。

1. 进程&子进程

1.1 什么是进程

计算机实际上可以做的事情实质上非常简单,比如计算两个数的和,再比如在内存中寻找到某个地址等等。这些最基础的计算机动作被称为指令 (instruction)。所谓的程序(program),就是这样一系列指令的所构成的集合。通过程序,我们可以让计算机完成复杂的操作。程序大多数时候被存储为可执行的文件。这样一个可执行文件就像是一个菜谱,计算机可以按照菜谱作出可口的饭菜。

那么,程序和进程(process)的区别又是什么呢?

进程是程序的一个具体实现。只有食谱没什么用,我们总要按照食谱的指点真正一步步实行,才能做出菜肴。进程是执行程序的过程,类似于按照食谱,真正去做菜的过程。同一个程序可以执行多次,每次都可以在内存中开辟独立的空间来装载,从而产生多个进程。不同的进程还可以拥有各自独立的IO接口。

操作系统的一个重要功能就是为进程提供方便,比如说为进程分配内存空间,管理进程的相关信息等等,就好像是为我们准备好了一个精美的厨房。

首先,我们可以使用 p s 命 令 来 查 询 正 在 运 行 的 进 程 , 比 如 ‘ ps命令来查询正在运行的进程,比如` ps命令来查询正在运行的进程,比如‘ps -eo pid,comm,cmd`,下图为执行结果:

(-e表示列出全部进程,-o pid,comm,cmd表示我们需要PID,COMMAND,CMD信息)

ok@u20:~/桌面$ ps -eo pid,comm,cmd
    PID COMMAND         CMD
      1 systemd         /sbin/init splash
      2 kthreadd        [kthreadd]
      3 rcu_gp          [rcu_gp]
      4 rcu_par_gp      [rcu_par_gp]
      5 netns           [netns]
      7 kworker/0:0H-ev [kworker/0:0H-events_highpri]
     10 mm_percpu_wq    [mm_percpu_wq]
    ...

    9995 systemd-udevd   /lib/systemd/systemd-udevd
  11641 systemd-logind  /lib/systemd/systemd-logind
  11672 gdm-session-wor gdm-session-worker [pam/gdm-launch-environment]
  11681 systemd         /lib/systemd/systemd --user
  11682 (sd-pam)        (sd-pam)
  15543 kworker/0:1-cgr [kworker/0:1-cgroup_destroy]
  15546 kworker/2:1-rcu [kworker/2:1-rcu_par_gp]
  15564 bash            bash test.sh
  15566 a.out           ./a.out
  15574 kworker/3:1-cgr [kworker/3:1-cgroup_destroy]
  15579 nautilus        /usr/bin/nautilus --gapplication-service
  15602 bash            bash
  15614 kworker/0:2-eve [kworker/0:2-events]
  15667 bash            bash
  15738 kworker/3:0-eve [kworker/3:0-events]

每一行代表了一个进程。每一行又分为三列。第一列PID(process IDentity)是一个整数,每一个进程都有一个唯一的PID来代表自己的身份。第二列COMMAND是这个进程的简称。第三列CMD是进程所对应的程序以及运行时所带的参数。

(第三列有一些由中括号[]括起来的。它们是内核的一部分功能,被打扮成进程的样子以方便操作系统管理。我们不必考虑它们。)

1.2 如何创建一个进程

实际上,当计算机开机的时候,内核(kernel)只建立了一个systemd进程。Linux内核并不提供直接建立新进程的系统调用。剩下的所有进程都是init进程通过fork机制建立的。新的进程要通过老的进程复制自身得到,这就是fork。fork是一个系统调用。进程存活于内存中。每个进程都在内存中分配有属于自己的一片空间 (address space)。当进程fork的时候,Linux在内存中开辟出一片新的内存空间给新的进程,并将老的进程空间中的内容复制到新的空间中,此后两个进程同时运行。

老进程成为新进程的父进程(parent process),而相应的,新进程就是老的进程的子进程(child process)。一个进程除了有一个PID之外,还会有一个PPID(parent PID)来存储的父进程PID。如果我们循着PPID不断向上追溯的话,总会发现其源头是systemd进程。所以说,所有的进程也构成一个以systemd为根的树状结构。

如下,我们查询当前shell下的进程

ok@u20:~/桌面$ ps -o pid,ppid,cmd
    PID    PPID CMD
  15667   13862 bash
  16323   15667 ps -o pid,ppid,cmd
ok@u20:~/桌面$ 

还可以用pstree命令来显示整个进程树:

ok@u20:~/桌面$ pstree
systemd─┬─ModemManager───2*[{ModemManager}]
        ├─NetworkManager───2*[{NetworkManager}]
        ├─VGAuthService
        ├─accounts-daemon───2*[{accounts-daemon}]
        ├─acpid
        ├─at-spi-bus-laun─┬─dbus-daemon
        │                 └─3*[{at-spi-bus-laun}]
        ├─at-spi2-registr───2*[{at-spi2-registr}]
        ├─avahi-daemon───avahi-daemon
        ├─bluetoothd
        ├─colord───2*[{colord}]
        ├─cron
        ├─cups-browsed───2*[{cups-browsed}]
        ├─cupsd
        ├─dbus-daemon
        ├─gdm3─┬─gdm-session-wor─┬─gdm-x-session─┬─Xorg───{Xorg}
        │      │                 │               ├─dbus-run-sessio─┬─dbus-daemo+
        │      │                 │               │                 └─gnome-sess+
        │      │                 │               └─2*[{gdm-x-session}]
        │      │                 └─2*[{gdm-session-wor}]
        │      ├─gdm-session-wor─┬─gdm-x-session─┬─Xorg───{Xorg}
        │      │                 │               ├─gnome-session-b─┬─ssh-agent
        │      │                 │               │                 └─2*[{gnome-+
        │      │                 │               └─2*[{gdm-x-session}]
        │      │                 └─2*[{gdm-session-wor}]
        │      └─2*[{gdm3}]
        ├─gjs───6*[{gjs}]
        ├─gnome-keyring-d───3*[{gnome-keyring-d}]
        ├─gsd-printer───2*[{gsd-printer}]
        ├─ibus-daemon─┬─ibus-engine-lib───3*[{ibus-engine-lib}]
        │             ├─ibus-engine-sim───2*[{ibus-engine-sim}]
        │                     ├─2*[kerneloops]
        ├─networkd-dispat
        ├─polkitd───2*[{polkitd}]
        ├─rsyslogd───3*[{rsyslogd}]
        ├─rtkit-daemon───2*[{rtkit-daemon}]
        ├─snapd───13*[{snapd}]
        ├─supervisord───bash───a.out
        ├─switcheroo-cont───2*[{switcheroo-cont}]
        ├─systemd─┬─(sd-pam)
        │         ├─dbus-daemon
        │         ├─goa-daemon───3*[{goa-daemon}]
        ├─systemd─┬─(sd-pam)
        │         ├─at-spi-bus-laun─┬─dbus-daemon
        │         │                 └─3*[{at-spi-bus-laun}]
        │         ├─at-spi2-registr───2*[{at-spi2-registr}]
        │         ├─gnome-session-c───{gnome-session-c}
        │         ├─gnome-shell───8*[{gnome-shell}]
        │         ├─gnome-shell-cal───5*[{gnome-shell-cal}]
        │         ├─gnome-terminal-─┬─2*[bash]
        │         │                 ├─bash───pstree
        │         │                 └─4*[{gnome-terminal-}]
        │         ├─goa-daemon───3*[{goa-daemon}]
        │         ├─xdg-document-po───5*[{xdg-document-po}]
        │         └─xdg-permission-───2*[{xdg-permission-}]
        ├─systemd-journal
        ├─systemd-logind
        ├─systemd-network
        ├─wpa_supplicant
        └─xdg-permission-───2*[{xdg-permission-}]
ok@u20:~/桌面$ 

fork通常作为一个函数被调用。这个函数会有两次返回,将子进程的PID返回给父进程,0返回给子进程。实际上,子进程总可以查询自己的PPID来知道自己的父进程是谁,这样,一对父进程和子进程就可以随时查询对方。

通常在调用fork函数之后,程序会设计一个if选择结构。

  • 当PID等于0时,说明该进程为子进程,那么让它执行某些指令,比如说使用exec库函数(library function)读取另一个程序文件,并在当前的进程空间执行 (这实际上是我们使用fork的一大目的: 为某一程序创建进程);
  • 而当PID为一个正整数时,说明为父进程,则执行另外一些指令。

由此,就可以在子进程建立之后,让它执行与父进程不同的功能。

1.3 子进程的终结(TERMINATION)

当子进程终结时,它会通知父进程,并清空自己所占据的内存,并在内核里留下自己的退出信息(exit code,如果顺利运行,为0;如果有错误或异常状况,为>0的整数)。在这个信息里,会解释该进程为什么退出。父进程在得知子进程终结时,有责任对该子进程使用wait系统调用。这个wait函数能从内核中取出子进程的退出信息,并清空该信息在内核中所占据的空间。但是,如果父进程早于子进程终结,子进程就会成为一个孤儿(orphand)进程。孤儿进程会被过继给init进程,init进程也就成了该进程的父进程。init进程负责该子进程终结时调用wait函数。

当然,一个糟糕的程序也完全可能造成子进程的退出信息滞留在内核中的状况(父进程不对子进程调用wait函数),这样的情况下,子进程成为僵尸(zombie)进程。当大量僵尸进程积累时,内存空间会被挤占

尽管在UNIX中,进程与线程是有联系但不同的两个东西,但在Linux中,线程只是一种特殊的进程。多个线程之间可以共享内存空间和IO接口。所以,进程是Linux程序的唯一的实现方式。

总结:
fork()/execve()过程中,假设子进程结束时父进程仍存在,而父进程fork()之前既没安装SIGCHLD信号处理函数调用waitpid()/wait()等待子进程结束,又没有显式忽略该信号,则子进程成为僵尸进程,无法正常结束,此时即使是root身份kill -9也不能杀死僵尸进程。补救办法是杀死僵尸进程的父进程(僵尸进程的父进程必然存在,否则子进程就会因为父进程的结束而变成了孤儿进程了),僵尸进程成为”孤儿进程”,过继给1号进程init,init始终会负责清理僵尸进程。

2. 进程关系

2.1 进程组

2.1.1 理论

每个进程都会属于一个进程组(process group,pg),每个进程组中可以包含多个进程。进程组会有一个进程组领导进程 (process group leader),也叫进程组长。进程组长的PID成为进程组的ID (process group ID, PGID),以识别进程组。

一般情况下,一个进程组是由一个进程 fork 出来的,之后,它的子进程再去 fork ,最后,得到了一个进程组。当然,单个的进程也是一个进程组。进程组有进程组 id ,它通常是第一个进程的 pid ,也就是组长进程的 pid (以识别进程组)。但是一个进程组的组长进程并不是一定要一直存在,当进程组长运行结束后,该进程组仍然存在,且进程组的id不变。

 

$ps -o pid,pgid,ppid,comm | cat
 PID  PGID  PPID COMMAND
17763 17763 17751 bash
18534 18534 17763 ps
18535 18534 17763 cat

PID为进程自身的ID,PGID为进程所在的进程组的ID, PPID为进程的父进程ID。从上面的结果,我们可以推测出如下关系:ps和cat进程构成18534进程组,组长为ps进程;bash单个进程构成一个进程组。同时,bash进程是ps和cat的父进程。进程组的领导进程的PID成为进程组ID。领导进程可以先终结。此时进程组依然存在,并持有相同的PGID,直到进程组中最后一个进程终结

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

2.1.2 API

进程组ID和进程ID相似:它们是正整型,并以pid_t类型存储。函数getpgrp返回调用进程的进程组ID。

#include <unistd.h>
/***********************
 *功能:获取进程组ID
 *返回值:成功返回进程组ID,失败返回-1并设置errno
 * *********************/
pid_t getpgrp(void);

在BSD后代系统的早期版本,getpgrp函数接受一个pid参数并返回这个进程的进程组。SUS定义getpgid函数作为一个XSI扩展来效仿这种行为。

/**************************
 * 功能:获取进程GID
 * 参数:pid ---- 进程ID
 * 		   如果pid为0,返回调用进程的进程组ID。因而getpgid(0)等价于getpgrp();
 * 返回值:成功返回进程组ID,失败返回-1并设置errno
 * ***********************/
pid_t getpgid(pid_t pid);

通过调用setpgid,可以让一个进程加入一个存在的进程组或创建一个新的进程组。

/*****************************
 * 功能: 设置进程组ID
 * 参数: pid进程ID
 *       pgid进程组ID
 *           如果pid的实参为0,setpgid(0, 5)等价于setpgid(getpid(), 5)
 *           如果pgid为0,setpgid( 5, 0)等价于setpgid( 5, getpid())
 * 返回值:成功返回0,错误返回-1
 * 注意:  一个进程只能为它自己或它的子进程设置进程组ID
 *        在它的子进程调用了exec后,它就不再能改变该子进程的进程组ID
 ****************************/
int setpgid(pid_t pid, pid_t pgid);

2.1.3 实践

KILL 进程组

一个进程所创建的子进程,都会被包含到一个进程组中。所以,我们可以用进程组杀死某个进程及其fork出的所有子进程。

ok@u20:~/桌面$ ps -eo pid,ppid,pgid,comm
   pid    ppid    pgid  comm
  15564     989   15564 bash
  15566   15564   15564 a.out
  15579   12965   12978 nautilus

我们以15564进程组为例,确实将该进程组的进程杀掉了。

$ kill -- -15564
或者$ kill -SIGTERM -- -15564

ok@u20:~/桌面$ kill -- -15564
ok@u20:~/桌面$ ps -eo pid,ppid,pgid,comm
    PID    PPID    PGID COMMAND
      1       0       1 systemd
      2       0       0 kthreadd
    ...
  15312       1   15312 snapd
  15476       1   15476 systemd-resolve
  15579   12965   12978 nautilus
  15602   13862   15602 bash
  15614       2       0 kworker/0:2-rcu_par_gp
  15667   13862   15667 bash

POSIX中的进程组

显示子进程与父进程的进程组id。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
    pid_t pid;
    printf("start fork......\n");
    if((pid=fork())<0){//第一次创建子进程
        perror("fork");
        exit(1);
    }else if(pid==0){//子进程
        printf("The child process PID is %d.\n",getpid());
        printf("The Group ID is %d.\n",getpgrp());
        printf("The Group ID is %d.\n",getpgid(0));
        printf("The Group ID is %d.\n",getpgid(getpid()));
    }else{//父进程
        sleep(3);
        printf("The parent process PID is %d.\n",getpid());
        printf("The Group ID is %d.\n",getpgrp());
    }
    exit(0);
}
ok@u20:~/test/forkTest$ ./fork1 
start fork......
The child process PID is 15700.
The Group ID is 15699.
The Group ID is 15699.
The Group ID is 15699.
The parent process PID is 15699.
The Group ID is 15699.

僵尸进程和孤儿进程的测试也可以在上述代码中展开,只不过需要修改一下结束顺序。这里面因为父进程后结束,而子进程结束,但是父进程没有设置wait()函数等接收子进程的结束信号,所以当子进程结束而父进程没有结束的时候,子进程会变成僵尸进程:

  16851   15602   16851 fork1           ./fork1
  16852   16851   16851 fork1 <defunct> [fork1] <defunct>
  16853   13892   16853 ps              ps -eo pid,ppid,pgid,comm,cmd

但是当父进程也结束后,两个进程都正常结束,应该是父进程正常退出,僵尸子进程变成1号进程的子进程,由1号进程进行了资源回收处理。

16833   16830   16830 a.out           ./a.out
  16872       2       0 kworker/0:2-cgr [kworker/0:2-cgroup_destroy]
  16876   13892   16876 ps              ps -eo pid,ppid,pgid,comm,cmd
ok@u20:~/桌面$ 

下面子进程使用setpgid()创建了一个新的进程组,并且进程组的组长就是自己。从而脱离了父进程的进程组:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{
    pid_t pid;
    printf("start fork......\n");
    if((pid=fork())<0){
        perror("fork");
        exit(1);
    }else if(pid==0){
        printf("Child:before setpgid,my pid=%d,My pgid=%d\n",getpid(),getpgrp());
        setpgid(getpid(),getpid());
        printf("Child:after setpgid,my pid=%d,My pgid=%d\n",getpid(),getpgrp());
    }else{
        wait(NULL);//等待子进程先结束,并处理其发送的sigchild信号
        printf("child exit\n");
        printf("Father:My pid=%d,My pgid=%d\n",getpid(),getpgid(getpid()));
    }
    exit(0);
}
ok@u20:~/test/forkTest$ ./fork2 
start fork......
Child:before setpgid,my pid=17007,My pgid=17006
Child:after setpgid,my pid=17007,My pgid=17007
child exit
Father:My pid=17006,My pgid=17006
ok@u20:~/test/forkTest$ 

 可以看出子进程可以设置自己为新的进程组长。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{
    pid_t pid;
    printf("start fork......\n");
    if((pid=fork())<0){
        perror("fork");
        exit(1);
    }else if(pid==0){
        printf("Child:before setpgid,my pid=%d,My pgid=%d\n",getpid(),getpgrp());
        sleep(2);
        printf("Child:after setpgid,my pid=%d,My pgid=%d\n",getpid(),getpgrp());
    }else{
        sleep(1);
        setpgid(pid,pid);
        wait(NULL);
        printf("child exit\n");
        printf("Father:My pid=%d,My pgid=%d\n",getpid(),getpgid(getpid()));
    }
    exit(0);
}
ok@u20:~/test/forkTest$ ./fork3
start fork......
Child:before setpgid,my pid=17033,My pgid=17032
Child:after setpgid,my pid=17033,My pgid=17033
child exit
Father:My pid=17032,My pgid=17032
ok@u20:~/test/forkTest$ 

2.2 会话 (SESSION)

2.2.1 理论

多个进程组构成一个「会话」,建立会话的进程是会话的领导进程,也叫会话组长,该进程 ID 为会话的 SID。会话中的每个进程组称为一个「作业」。会话可以有一个进程组称为会话的「前台作业」,其它进程组为「后台作业」

一个会话可以有一个控制终端,当控制终端有输入和输出时都会传递给前台进程组,比如Ctrl + Z。会话的意义在于能将多个作业通过一个终端控制,一个前台操作,其它后台运行。

进程组(工作)的概念较为简单易懂。而会话主要是针对一个终端建立的。当我们打开多个终端窗口时,实际上就创建了多个终端会话。每个会话都会有自己的前台工作和后台工作。这样,我们就为进程增加了管理和运行的层次。在没有图形化界面的时代,会话允许用户通过shell进行多层次的进程发起和管理。比如说,我可以通过shell发起多个后台工作,而此时标准输入输出并不被占据,我依然可以继续其它的工作。如今,图形化界面可以帮助我们解决这一需求,但工作组和会话机制依然在Linux的许多地方应用。

2.2.2 API

1、一个进程通过调用setsid函数来建立一个新的会话。

#include <unistd.h>
pid_t setsid(void);
//返回值:成功返回会话ID;出错返回-1

①如果调用此函数的进程不是一个进程组组长,则此函数创建一个新会话:

  • 此进程变成该新会话的会话首进程(session leader,会话首进程是创建该会话的进程,也就是会话组长)。此时,该进程是该会话中的唯一进程

  • 此进程成为一个新进程组的组长进程。新进程组ID是该调用进程的进程ID

  • 此进程没有控制终端。如果在调用setsid之前此进程有一个控制终端,那么这种联系也被解除

②如果调用此函数的进程是一个进程组组长,则此函数出错返回

  • 为了保证不处于这种情况,通常先调用fork,然后使其父进程终止,而子进程则继续。因为子进程继承了父进程的进程组ID, 而其进程ID则是新分配的,两者不可能相等,所以这就保证了子进程不是一个进程组的组长

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

2、获取会话首进程的进程组ID(getsid函数)

#include <unistd.h>

//返回值:成功返回会话首进程的会话ID;失败返回-1
pid_t getsid(pid_t pid);
 

2.2.3 实践

会话ID

例如:下面的一个会话中,有3个进程组

通常是由shell的管道线将几个进程编成一组的,则上图的安排可能是由下列形式的shell命令形成的
 

 2.2.4 Shell中的前台后台进程

一个命令可以通过在末尾加上&方式让它在后台运行:

$ ping localhost > log &
[1] 4345     # 括号中的1表示工作号,而10141为PGID
$ ps -o pid,pgid,ppid,sid,tty,comm
   PID   PGID   PPID    SID TT       COMMAND
  3772   3772   3764   3772 pts/0    bash
  4345   4345   3772   3772 pts/0    ping
  4355   4355   3772   3772 pts/0    ps

信号可以通过kill的方式来发送给工作组。上面的两个命令,一个是发送给PGID(通过在PGID前面加-来表示是一个PGID而不是PID),一个是发送给工作1(%1),两者等价。

$kill -SIGTERM -4345
或者
$kill -SIGTERM %1

一个工作可以通过$fg从后台工作变为前台工作:

$cat > log &

$fg %1

当我们运行第一个命令后,由于工作在后台,我们无法对命令进行输入,直到我们将工作带入前台,才能向cat命令输入。在输入完成后,按下CTRL+D来通知shell输入结束。

linux-创建子进程的过程与原理(fork讲解) 两个原因,首先在进程载入内存中的代码区,这个区域与常量区,在内存期间代码是不可被修改的,如果每创建一个子进程占用内存代码区一部分资源,这是非常浪费内存资源的,所以操作系统在创建子进程时候,使得子进程与其父进程共享一份代码。在代码创建的时候,子进程的内核数据结构是拷贝父进程的,而代码段父子进程共享,然后数据段的内容,在未发生写入时候父子共享,在发生写入时拷贝数据,子进程数据信息独立(写时拷贝)。我们知道,子进程可以被命令行创建,被fork函数创建,但是子进程创建了什么呢,是完全拷贝父进程函数? 阅读详情

相关推荐

Linux系统编程(进程组

本篇文章我们开始学习Linux中的进程组进程组这个概念可能很多小伙伴都没有接触过,那么这篇文章将会教大家什么是进程组。本篇文章主要给大家讲解了进程组概念学习了如何修改进程组的依附性。

m0_49476241的博客 1737

进程子进程

进程子进程子进程有独立的数据段、堆、栈,共享代码段 Linux中每个进程都有4G的虚拟地址空间(独立的3G用户空间共享的1G内核空间),fork()创建的子进程也不例外。子进程资源的由来: 1G内核空间既然是所有进程共享,因此fork()创建的子进程自然也将拥有; 3G的用户空间是从父进程进程而来。 进程fork写时复制 fork()创建子进程时继承了父进程的数据段、代码段、栈段、堆,注意从父进程继承来的是虚拟地址空间,同时也复制了页表(没有复制物理块)。因此,此时父子进程拥有相同的虚拟地址,

浅夜 2977

Linux系统编程(会话进程

本篇文章我们来讲解会话进程概念会话大家可能比较少见,他的英文名称叫session。本篇文章就讲解到这里。

m0_49476241的博客 1489

来自root 的进程对 CPU占用高解决方法

有时候,CPU 占用很高,而且是root的进程。比如 top Tasks: 558 total, 1 running, 557 sleeping, 0 stopped, 0 zombie %Cpu(s): 61.4 us, 0.0 sy, 0.0 ni, 38.6 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem : 13191446...

七爷OK 7459

Linux】守护进程

我们在写完一些网络服务后,如果想让这个服务一直在云服务器的后台运行着,那该如何实现呢?其实就用到了这篇博客要讲的守护进程

2201_76024104的博客 1624

Linux----进程组

ProcessGroup ​ Linux系统一般都是作为服务器而存在,对于Linux系统而言,图形化界面不过是一个内核之外给“普通用户”增加使用体验感的一个道“道具”而已,这个“道具”Windows系统一样,对于一个小白而言上手即可使用,只不过Windows的图形界面是内核之内的,而Linux系统的图新界面是内核之外的。由于设计的初衷不同,作为服务器的Linux系统,使用图形化界面是没有任何对服务器性能提升的作用的,所以摒弃图形化界面一个Linux使用者所要秉持的原则 所以很多时候对Linux系统的使用常

qq_45699770的博客 580

linux php 进程进阶(六)进程组

linux php 进程进阶(六)进程组 进程组 进程组 进程组,就是一个或是多个进程的集合,一个进程都有一个标识组ID,表示该进程属于哪个进程组 bash进程启动之后,它会自己setsid把自己设置为会话进程,也会设置自己为组长进程 // 获取当前进程pid $pid = posix_getpid(); // 打印当前进程pid,父进程pid,进程组pgid,会话sid fprintf(STDOUT,"pid=%d,ppid=%d,pgid=%d,sid=%d ",$pid,posix_getp

m0_67402823的博客 768

Linux进程之间的关系

一、进程组概念 Linux下每个进程(PID)都隶属于一个进程组(PGID)。每个进程组都有一个首领进程,首领进程的特点是PGIDPID相同。进程组是一直存在的,除非进程组里面的进程都退出了,或者加入到其他进程组中。一个进程能够设置自己或者其子进程的PGID,另外,当子进程调用了exec系列函数之后,父进程也不能设置子进程的PGID。 二、会话 会话(SID)是由一系列有关联的进程组组成。可通过setsid()函数创建一个会话。但是一个进程组的首领是不能调用这个会话的,只能是非进程组首领的进程才可以调用

qq_43363657的博客 862

Linux进程层次分析

/设置进程的组标识。// 获取当前进程的组标识。// 获取指定进程的组标识。pid == pgid,将pid指定的进程设为组长。pid == 0,设置当前进程的组标识。pgid ==0,则将pid作为组标识。

weixin_42136255的博客 648

4-Linux 进程组的精确理解 Daemon进程

为了验证 if you log into a machine, your shell starts a session from: https://blog.csdn.net/cpxsxn/article/details/107371177。为了验证 os.setsid();executor.py 主体就是一个真正的 daemon 进程。shell 进程: http://c.biancheng.net/view/739.html。为了验证:父子进程是一个进程组,但是子进程不是进程组组长。

cpxsxn的博客 576

Linux专栏_5】Linux进程间关系守护进程

可以看到当一开运行进程的时候,父进程延时5秒的,此时进程有自己的PPID、PID、PGID,由于是单进程所以是自己的PID,当5秒结束后,创建子进程,让父进程直接退出,此时该进程就变为了孤儿进程,被1号进程领养,但所属的进程组ID是不变的,还是第一个进程运行的PID,只是PID变为了子进程的PID了。总结就是:当多个进程在运行时候,他们有各自的PPID、PID,但是PGID是相同的,因为是一个进程组,并且规定进程组ID就是第一进程执行时的PID。一个作业可以包含一个进程或者是进程组进程之间相互协调。

2301_78704584的博客 879

操作系统进程线程(二)—父子进程、僵尸进程、孤儿进程进程终止、守护进程

已创建一个或者多个进程

qaaaaaaz的博客 2008

setsid命令以及会话与守护进程概念

linux常用的命令 setsid命令的一般格式: setsid(); 说明:当进程会话的领头进程时setsid()调用失败并返回(-1)。setsid()调用成功后,返回新的会话的ID,调用setsid函数的进程成为新的会话的领头进程,并与其父进程会话进程组脱离。由于会话对控制终端的独占性,进程同时与控制终端脱离。 pid_t pid = fork(); //fo

崔行兵的专栏 2153

linux php 进程进阶(七)sid(会话)

说起会话,我们经常登录到linux系统, linux是一个多用户多任务的分时操作系统,必须要支持多个用户同时登陆同一个操作系统,当一个用户登陆一次终端时就会产生一个会话,执行各种各样的程序,这都牵涉到会话会话是基于连接的。会话的源头,就是用户与系统之间连接的启用。每个会话有一个会话进程,即创建会话进程,建立与终端连接的就是这个会话进程,也被称为控制进程。一个会话可以包括多个进程组, 这些进程组可被分为一个前台进程组一个或多个后台进程组。为什么要这么分呢?前台进程组是指需要与终端进行交互的进程组

专注于php高级知识分享 807

Linux会话

控制终端与会话中的所有进程相关联、绑定,控制、影响着会话中所有进程的一些行为特性譬如控制终端产生的信号,将会发送给该会话中的进程(譬如 CTRL+C、CTRL+Z、CTRL+\产生的中断信号、停止信号、退出信号,将发送给前台进程组);2、调用 setsid 函数除了创建新的会话之外、也会创建一个新的进程组 (因为一个会话至少要存在一个进程组),而调用该函数的进程也是这个进程组的组长进程。1、如果调用该函数的进程不是进程组的组长进程,那么调用该函数会创建一个新的会话调用该函数的进程会成为新会话会话首领!

wn418@outlook.com 241

守护进程——后台服务进程

echo $$:可以查看当前进程进程号。

大脑曝光 871

03_Linux进程

进程:可执行文件从运行到结束这段过程就叫进程进程运行在系统上,占用内存空间,是动态的。程序存储在磁盘上,占用磁盘空间是静态的。进程运行时,内核为进程每个进程分配一个PCB(进程控制块),维护进程相关的信息。进程id标记每一个进程,0进程在内核中,1号进程在用户态,用户的所有进程都是由1号进程分配控制得来。进程的状态分为:等待态、就绪态、执行态等待态:进程正在等待CPU能调用的条件成立。就绪态:进程被调度的条件成立,等待CPU调度。执行态:进程的正在被CPU执行。查看进程状态:ps。

qq_43612373的博客 820

Linux学习之进程

进程状态;前台进程,后台进程;父进程子进程;创建进程,查找进程,杀死进程;fork,system,exec;进程组,作业,会话,SIGHUP;作业命令:jobs、ctrl + z、bg、fg、disown;init进程,孤儿进程,守护进程,僵尸进程;命令:pidof、kill、pkill、killall、&、nohup、setsid、daemonize、screen、tmux;

lonelymanontheway的博客 1677
上一篇: linux设置开机启动脚本的3种方法
下一篇: linux守护进程以及如何编写守护进程程序
土豆西瓜大芝麻
博客等级 码龄18年 1151粉丝 238原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值