终端与作业控制

来源:互联网 发布:网络推广的案例 编辑:程序博客网 时间:2024/06/05 16:13

进程组

 

1)简单来说进程组就是多个进程组成的集合

2)和进程一样,进程有唯一的PID进行表识,同样进程组也有一个唯一的标识就是进程组ID,即每个组长的ID(组长ID一般是该组的第一个进程的ID)

3)进程组的生命周期:一个进程组是用组长ID进行标识的,但是不要错误的认为组长进程结果,该进程组就结束;而进程组的生命周期是取决于该组中最后一个退出的进程,只要该组还有一个进程就认为该进程组是存在的。

4)获取进程组ID的方法:getpgid或者getpgrp

#include <unistd.h>pid_t getpgid(pid_t pid);//成功返回进程组ID,失败返回-1pid_t getpgrp(void);

5)一个进程组可以为自己或者子进程设置进程组ID(如果不设置的话,默认为该进程组的第一个进程ID)

#include <unistd.h>int setpgid(pid_t pid, pid_t pgid);//成功返回0,失败返回-1

代码演示:

父进程创建出一个子进程,然后通过getpgrp或者getpgid来获取当前进程组的组长ID,查看当前进程组的组长ID

#include<stdio.h>#include<unistd.h>#include<stdlib.h>int main(){        int id=fork();        if(id==0){                printf("i am a child, my pid is %d,my parent id is %d\n",getpid(),getppid());                printf("i am a child, my pid is %d,my group id is %d\n",getpid(),getpgrp());                printf("i am a child, my group id is %d,my parent id is %d\n",getpgid(getpid()),getppid());        }        else if(id>0){                printf("i am a parent, my pid is %d,my parent id is %d\n",getpid(),getppid());                printf("i am a parent, my id is %d, my group id is %d\n",getpid(),getpgid(getpid()));                exit(1);        }        return 0;}
运行结果(默认为该进程组的第一个进程ID)



作业

 

1)作业的本质还是进程的集合,不过在将进程和作业进行对比时这些说法就不那么正确了,因为shell分前后台运行的不是进程而是作业;

2)作业控制:shell可以同时运行一个前台作业和多个后台作业;

3)不管是前台作业还是后台作业,都可以由多个进程组成;

4)在一个作业中新创建一个进程,该进程属于作业不属于进程组。

 

代码演示:

父进程创建一个子进程,然后父进程直接退出,如果作业中的某个进程创建的子进程程属于进程组而不属于作业的话,那么父进程退出的话,子进程应该代替父进程成为新的前台进程运行。


运行结果

当父进程结束后,子进程被1号进程所领养,但子进程不在属于该进程组而是属于作业,同时使用组合键ctrl+c时不能终止该进程,说明其子进程是一个后台进程,要杀掉该作业只能通过kill命令向其发送相应的信号



使用kill命令杀死子进程演示:

为了防止输出队列冲散输入队列的输入效果,重新打开一个终端进行kill命令的执行



会话(SID)

 

1)一个或者多个进程组的集合称为一次会话;

2)可以简单的理解一个会话就是一个终端,而Linux下一切皆文件,所以不同的终端其本质是相当于一个个不同的普通文件;

3)会话控制:一次会话中包括一个前台进程组,任意多个后台进程组和控制进程;

4)控制进程:建立与控制终端连接的会话首进程被称为控制进程。

5)新建一个终端的过程就是新建一个会话


代码实现:

 

运行结果:



查看系统中新建终端会话的数量:ps axj

新建一个会话的过程就是新建一个终端的过程,而新建终端必然会产生一个bash,因此直接过滤出来当前系统下的bash即可


原创粉丝点击