本篇索引:

1、引言

2、终端登录

3、进程组

4、会话期

1、引言

通过上一篇的学习,我们已经知道了如何控制一个进程,fork函数从父进程中复制出子进程,我们可以通过exec函数让子进程运行新的程序,进程可以通过调用exit系列函数(return,_exit)终止,父进程可以利用wait或waitpid函数等待某个进程的终止状态。

在操作系统上同时运行着很多的进程,那么这些进程之间有没有什么什么关系呢?答案是肯定的,最起码这些进程之间是有父子关系的,当然只这里要除掉0、1、2这三个进程。

那么本篇的主要内容就是进一步讨论这些进程之间的相互关系。

2、终端登录

大家现在登陆一个linux操作系统已经熟练了,只要输入用户名和密码即可,但是对于这个的登陆的过程就不是很熟悉了,我们通过RS-232终端登陆的过程来窥见下这个具体的登陆过程是怎样的。

 

3、进程组

进程组是一个进程或多个进程的集合,每个进程还属于某个唯一的进程组,组ID就是进程组组长的进程ID,getpgrp函数可以返回当前进程所在进程组的组ID。

3.1、getpgrp函数

1)、函数原型和所需头文件

#include <unistd.h>

pid_t getpgrp(void);

2)、函数功能:获取调用该函数的当前进程所在进程组的组ID。

3)、函数参数:无参数。

4)、函数返回值:成功,返回当前进程所在进程组的组ID,失败返回-1,errno被设置。

5)、注意:

a)、即使是组长死了,但只要该组中还有一个组员进程正在运行,那么进程组依然存在。

B)、从进程组创建到该组中最后一个进程结束的这段时间,我们称为进程组的生命期。

c)、从shell终端开始运行的第一个进程担任组长,其进程ID就是组ID,随后从该进程fork   出的所有的进程全部属于该组。

d)、当然除了组长进程外任何一个组员都能够通过调用setpgid函数自成一组或则加入其   它组。

6)、测试用例

test.c

#include <stdio.h>
#include <unistd.h> int main(void)
{
int ret = ;
ret = fork();
if( == ret) //原始父进程的第一个子进程
{
ret = fork();
if( == ret){
printf("pgrp = %d\n", getpgrp());
}
else if(ret > ){
printf("pgrp = %d\n", getpgrp());
}
}
else if(ret > ){
ret = fork(); //原始父进程的第二个子进程
if( == ret){
printf("pgrp = %d\n", getpgrp());
}
else if(ret > ){ //原始父进程
sleep();//让所有子进程先运行结束
printf("pgrp = %d\n", getpgrp());
}
}
return ;
} return ;
}

上例运行结果如下:

pgrp = 4163

pgrp = 4163

pgrp = 4163

pgrp = 4163

可以看出所有进程都同属于一个组,组长由原始父进程担任,从原始父进程复制出来所有的进程都属于该组。

3.2、setpgid函数

1)、函数原型和所需头文件

#include <unistd.h>

pid_t getpgid(pid_t pid, pid_t pgid);

2)、函数功能:调用该函数以指定某个进程参加一个现存的组或者创建一个新的进程组。

3)、函数参数

pid_t pid:指定需要被修改为或设置到新进程组的进程。

pid_t pgid:进程组ID,指定某个进程组。

4)、函数返回值:成功返回进程组的组ID,失败返回-1,errno被设置。

5)、注意:

这个函数的功能是将pid进程的进程组修改为pgid对应的进程组。但是需要注意如下特殊情况。

1、当这两个参数相等时,则将pid对应的进程直接的变为进程组组长。

2、pid填0的话,pid默认使用调用者的进程ID。

3、Pgid填0的话,pgid默认使用pid指定的进程ID为进程组ID。

4、一个进程只能为它自己或者子进程设置进程组ID,但是子进程一旦exec之后就不能 再改变它的进程组ID了。

6)、例子

a)、在shell命令行执行了新的程序之时,shell会fork出子进程以运行新的程序,shell 父进程会调用该函数将子进程设置为新的进程组组长,子进程也会调用该函数将自己设 置为新的进程组组长,这两个操作有一个冗余的,但是这能够保证无论父子进程谁先运 行,子进程都能被设置为新的进程组组长,否者的话就会产生一个竟态,结果就会依赖 于哪一个进程先运行,之后从该子进程复制出的所有的子进程都属于该进程组。

b)、测试用例

#include <stdio.h>
#include <unistd.h> int main(void)
{
int ret = ;
ret = fork();
if( == ret){ //原始父进程的第一个子进程
setpgid(getpid(), getpid());
printf("in chaild pgrp = %d\n", getpgrp());
}
else if(ret > ){ //原始父进程,有shell父进程复制而来
sleep();
printf("in pareant pgrp = %d\n", getpgrp());
}
return ;
}

程序运行结果如下:

in child pgrp = 7930

in pareant pgrp = 7929

本来复制出来的子进程和原始父进程同属于一个进程组,原始父进程亲自担任组长,但是子进程由于调用setpgid(getpid(), getpid());将自己变成了一个新的进程组,自己亲自担任组长,所以我们看到这里的父子进程各自都属于自己的一组,所以此后从子进程复制出的子进程就会属于新的一组,父进程父子出的子进程属于父进程这一组。

4、会话期

我们知道一个或多个进程组合在一起就组成为了一个进程组,但当多个进程组被组合在一起的集合,这个集合就被称为会话期,如下图所示,该会话期中有三个进程组,进程组之间由shell管道线连接组成。

4.1、setsid函数

1)、函数原型和所需头文件

#include <unistd.h>

pid_t setsid(void);

2)、函数功能:将调用该函数的进程变成一个新的会话期,但是进程组组长不能被设置为一 个新的会话期。

3)、函数参数:无参数。

4)、函数返回值:成功,返回新的会话期ID,失败返回-1,errno被设置。

5)、注意

·进程组中担任组长的进程不能被设置为新的会话期,组长调用了该函数后会出错返回, 为了避免这种情况的发生,通常先fork出子进程,然后使其父进程终止,子进程继续运 行,新的子进程与父进程同属于一个进程组,但是子进程不可能是进程组组长。

·创建新的会话期的进程就是会话期的首进程,会话期ID就是该进程的进程ID。

·会话期首进程也成为了会话期中第一个进程组中的组长。

·此进程没有控制进终端,如果在调用setsid函数之前此进程有一个控制终端,那么这 种关系也会被解除了。

6)、测试用例

5、控制终端

5.1、会话期的特点

1)、一个会话期可以有一个控制终端,这个通常是我们登录的终端设备或伪终端设备。

2)、建立与控制终端连接的对话器首进程被称为控制进程。

3)、一个会话期中的多个进程组被分为一个前台进程组和一个或多个后台进程组。

4)、一个会话期可以有0个或1个前台进程组,但是至少要有一个后台进程组。

5)、如果会话期有控制终端的话,一定有一个前台进程组,前台进程组有与控制终端交互的   权利,其它所有的进程组的都是后台进程组。

6)、无论何时按下中断键(ctrl+c或ctrl+\),其参生的SIGINT或SIGQUIT信号被发送前台   进程组中的所有进程。

7)、如果中断界面已经检测到调制解调器已经脱离或则终端已经断开,则挂断信号会被   送至控制进程。

例子说明:

1、当我们打开一个终端时,这个终端本身就是一个运行的进程,该进程创建了一个新的会话期, 该shell进程就是创建此会话期的首进程,也是控制进程,这个会话期中就只有一个进程组,就 是会话期首进程所在的组,也是前台进程组,这时我们能够直接输入shell命令到shell终端,因 为前台进程组拥有与控制终端交互的权利。

2、当我们./a.out在该shell终端上运行新的程序时,不加&,不把程序放到后台运行的情况下, 该程序的第一个进程独自成立一组自己亲自担任组长,它所复制出来的进程均属于这一进程组, 该进程组就变为了前台进程组,我们拥有与前台该进程组的组长进程的终端交互权,如果我们将 新程序放到后台运行的话(如./a.out &)。新运行的程序创建出的新的一组属于后台进程组,shell 终端命令行仍然控制着终端交互权。

3、从新运行的程序所在进程组中分列出的所有的进程组全部都将变为后台进程组。

linux_api之进程环境(二)的更多相关文章

  1. linux_api之进程环境

    本篇索引: 1.引言 2.main函数 3.进程的终止方式 4.exit和_exit函数 5.atexit函数 7.环境表 8.C程序程序空间布局 9.存储空间的手动分配 10.库文件 1.引言 一个 ...

  2. (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  3. Linux进程环境

    Linux下C程序都是main开始的,main函数的原型是: int main(int argc, char **argv) 其中argc是命令行参数的数目,argc是指向参数的各个指针所构成的数组. ...

  4. Unix环境高级编程(五)进程环境

    本章主要介绍了Unix进程环境,包含main函数是如何被调用的,命令行参数如何传递,存储方式布局,分配存储空间,环境变量,进程终止方法,全局跳转longjmp和setjmp函数及进程的资源限制. ma ...

  5. Unix编程第7章 进程环境

    准备雄心勃勃的看完APUE,但是总感觉看着看着就像进入一本字典,很多地方都是介绍函数的用法的,但是给出例子远不及函数介绍的多.而且这本书还是个大部头呢.第7章的讲的进程环境,进程是程序设计中一个比较重 ...

  6. Linux/UNIX之进程环境

    进程环境 进程终止 有8种方式使进程终止,当中5中为正常终止,它们是 1)      从main返回 2)      调用exit 3)      调用_exit或_Exit 4)      最后一个 ...

  7. Qemu搭建ARM vexpress开发环境(二)----通过u-boot启动Linux内核

    Qemu搭建ARM vexpress开发环境(二)----通过u-boot启动Linux内核 标签(空格分隔): Qemu ARM Linux 在上文<Qemu搭建ARM vexpress开发环 ...

  8. Linux进程管理(二)

    目录 Linux进程管理(二) 参考 vmstat命令 top命令 Linux进程管理(二)

  9. 《UNIX环境高级编程》(APUE) 笔记第七章 - 进程环境

    7 - 进程环境 Github 地址 1. main 函数 C 程序总是从 main 函数 开始执行: int main(int argc, char *argv[]); \(argc\) 为命令行参 ...

随机推荐

  1. java中为什么要使用代理

    引入代理: 我们为什么要引入java的代理,除了当前类能够提供的功能外,我们还需要补充一些其他功能. 最容易想到的情况就是权限过滤,我有一个类做某项业务,但是由于安全原因只有某些用户才可以调用这个类, ...

  2. [转]Programmatically Register Assemblies in C#.

    1. Introduction. 1.1 After publishing Programmatically Register COM Dlls in C# back in 2011, I recei ...

  3. arp欺骗进行流量截获-2

    上一篇讲了原理,那么这一篇主要讲如何实现.基本上也就是实现上面的两个步骤,这里基于gopacket实现,我会带着大家一步步详细把每个步骤都讲到. ARP 欺骗 首先就是伪造ARP请求,让A和B把数据包 ...

  4. c++多线程基础4(条件变量)

    条件变量是允许多个线程相互交流的同步原语.它允许一定量的线程等待(可以定时)另一线程的提醒,然后再继续.条件变量始终关联到一个互斥 定义于头文件 <condition_variable> ...

  5. 洛谷P3355 骑士共存问题(最小割)

    传送门 de了两个小时的bug愣是没发现错在哪里……没办法只好重打了一遍竟然1A……我有点想从这里跳下去了…… 和方格取数问题差不多,把格子按行数和列数之和的奇偶性分为黑的和白的,可以发现某种颜色一定 ...

  6. MD5和SHA-1

    MD5和SHA-1都是我们耳熟能详的术语了,很多人可能知道他们跟加密有关系,但是他们是怎么做到加密的,他们各自的特点又是什么.我来简单的讲一讲. MD5和SHA-1都被称作哈希(Hash)函数,用过J ...

  7. node创建一个简单的web服务

    本文将如何用node创建一个简单的web服务,过程也很简单呢~ 开始之前要先安装node.js 1.创建一个最简单的服务 // server.js const http = require('http ...

  8. 用python的正则表达式实现简单的计算器功能

    #!/usr/bin/env python # -*- coding:utf-8 -*- import sys import re def welcome_func(): ""&q ...

  9. CF702F T-Shirts FHQ Treap

    题意翻译 题目大意: 有n种T恤,每种有价格ci和品质qi.有m个人要买T恤,第i个人有vi元,每人每次都会买一件能买得起的qi最大的T恤.一个人只能买一种T恤一件,所有人之间都是独立的.问最后每个人 ...

  10. Qt 学习之路 2(30):Graphics View Framework

    Qt 学习之路 2(30):Graphics View Framework 豆子 2012年12月11日 Qt 学习之路 2 27条评论 Graphics View 提供了一种接口,用于管理大量自定义 ...