MyException - 我的异常网
当前位置:我的异常网» C语言 » APUE 二

APUE 二

www.MyException.Cn  网友分享于:2013-09-28  浏览:0次
APUE 2

 

进程组(process group)

进程组顾名思义是指一个或多个进程的集合。他们通常与同一个job(可以从同一个终端接收信号)相关联。每个进程组拥有一个唯一的Process Group Id。可以使用getpgrp或getpgid获取进程的Process Group Id:

 1 #include <unistd.h>
 2 
 3 /*
 4 返回调用进程的进程组Id
 5 */
 6 pid_t getpgrp(void);
 7 
 8 /*
 9 若pid为0,作用与getpgrp相同
10 */
11 pid_t getpgid(pid_t pid);

每个进程组可以有一个进程组leader,leader的进程Id与其进程组id相同。无论进程组leader是否终止,只要进程组中存在未终止的进程这个进程组就不会消失。进程组leader终止后进程组中便不存在进程组leader,它不会自动推选新的进程组leader。参见 : Must a process group have a running leader process? 

可以通过setpgid函数设置进程组Id:

1 #include <unistd.h>
2 
3 /*
4 设置pid所在进程组Id为pgid
5 */
6 int setpgid(pid_t pid, pid_t pgid);

调用进程只能设置他自己和他的子进程的Process Group Id,并且如果他的子进程调用了exec类函数,那么调用进程也无法更改它的这个子进程的Process Group Id。在 job-control shells中,这个方法常用于fork调用后父进程来设置子进程的Process Group Id,或者子进程设置它自己的Process Group Id。当然,fork调用后子进程是会继承父进程的Process Group Id的,fork后setpgid目的是为了确保子进程的Process Group Id而避免因为并发竟态导致的意外(这个地方不太懂,没构建出作者设想的竟态环境)。

 

 

会话(session)

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

上图所示的session结构可以使用shell中的pipeline来表示:

proc1 | proc2 &
proc3 | proc4 | proc5

在上面示例中,login shell所在的进程组和proc1、proc2所在的进程组为后台进程组, proc3,proc4,proc5所在的进程组为前台进程组。一个会话中只能有一个前台进程组,可以有一个或多个后台进程组。关于前台进程组与后台进程组我们在后面介绍。

进程可以通过setsid来创建新的session。

1 #include <unistd.h>
2 
3 /*
4 成功,返回进程组ID,否则返回 -1
5 */
6 pid_t setsid(void);

setsid函数成功时返回的是调用进程的Process Group Id,也是调用进程的Process Id, 因为session leader 永远是它所在的进程组leader。其实UNIX中是没有类似 Process Id 或 Process Group Id 的 "Session Id" 这个东西的,有的仅仅是"Session leader"。 我们可以认为 session leader 的 Process Group Id 或 Process Id为其所在 session 的 Session Id。

setsid在调用时有3件事会发生:
  • 调用进程成为新session的session leader(A session leader is the process that creates a session)。此时此进程是新session中的唯一进程。
  • 调用进程成为新进程组的leader。新进程组的Process Group ID 等于 调用进程的 Process ID。
  • 调用进程不会再有控制终端。如果调用进程在调用setsid前拥有控制终端的话,那么调用setsid后他将断开与其控制终端的联系。
进程组leader不可以调用setrsid,如果调用者是进程组leader,那么setsid会返回一个error(大概因为一个进程不可以是两个进程组的leader?)。为了保证setsid的调用者不是进程组Id,许多实现通过调用fork,然后终止父进程,使子进程继续执行。我们可以保证此时子进程不会是任何进程组的leader。因为子进程继承父进程的进程组,而子进程的Process Id 是新产生的,因此子进程的Process Id 不可能与其继承的Process Group Id 相同。
可以通过getsid函数获取session leader 的 Process Group Id:
1 #include <unistd.h>
2 
3 /*
4 获取pid所在session的session leader
5 的Process Group ID
6 */
7 pid_t getsid(pid_t pid);

 

 

控制终端(controlling terminal)

 

session和进程组还有其他几个特性:
  • 一个session可以拥有一个控制终端(当然也可以没有)。他通常是我们登录时的终端设备或伪终端。
  • 创建与控制终端的链接的session leader被称为控制进程 (Controlling Process)。
  • 一个会话中的进程组可以划分为一个前台进程组和一个或多个后台进程组。
  • 如果一个会话拥有控制终端,那么它有一个前台进进程组,这个会话中的其他进程组都是后台进程组。
  • 无论何时我们按下终端的中止键(通常是 DELETE或Crtl-C),就会有一个中止信号发送给前台进程组中的所有进程。
  • 无论何时我们按下终端的退出键(通常是Crtl-Backslash),就会有一个退出信号发送给前台进程组中的所有进程。
  • 如果终端接口检测到网络断开,那么hang-up信号就会发送给控制进程,即the session leader。
下图描述了这些特性:

一般我们不必关心控制终端,它在我们登录时自动被创建。有事程序需要与控制终端通信,无论是使用标准输出还是标准输入重定向。程序保证与控制终端进行通信的方法时读写 /dev/tty文件。这个特殊文件在内核中是控制终端的代名词。如果程序没有控制终端,那么它打开/dev/tty文件将会失败。
可以使用tcgetpgrp函数获取前台进程组Id,使用tcsetpgrp设置前台进程组:

 1 #include <unistd.h>
 2 
 3 /*
 4 通过打开终端的文件描述符获取前台进程组Id
 5 */
 6 pid_t tcgetpgrp(int fd);
 7 
 8 /*
 9 pgrpid 必须是相同session中的一个进程组Id
10 */
11 int tcsetpgrp(int fd, pid_t pgrpid);

关于session、process group、controlling terminal的更多信息 , 参见:The controlling-terminal and process-groups.

 

 

Job Control

 

job control 允许我们在一个终端中启动多个job,我们可以控制哪些job可以接触到终端,哪些在后台运行。job control 要求3中形式的支持:
  1. shell需要支持job control
  2. 内核中的终端驱动必须支持job control
  3. 内核必须支持确定的job-control信号
对我们而言,当我们在shell中使用job control时,我们可以在前台或后台启动job。一个job仅仅是一些进程的集合,通常是一些使用pipeline连接的进程。
例:
# 在前台启动包含一个进程的job
vi main.c
# 两个后台jobs调用的所有进程都是后台进程
pr *.c | lpr &
make all &

# 当我们启动一个后台job时,shell会给这个job分配一个job id,
# 并打印这个job中的一个或多个进程IDs
$ make all > Make.out &
[1]    1475
$ pr *.c | lpr &
[2]    1490
终端驱动可识别3种特殊字符以产生发送给前台进程组的信号:
  • 中止字符(通常是DELETE或Crtl-C)产生SIGINT
  • 退出字符(通常是Crtl-Backslash)产生SIGQUIT
  • 暂停字符(通常是Crtl-Z)产生SIGSTP

如前所述,只有前台job会接收到终端输入,但是后台job尝试读取终端并不是错误的,终端驱动会检测后台进程的这种举动并向后台job发送一个特殊的信号:SIGTTIN。SIGTTIN通常会中止后台job。

总结

    前面我们讨论了进程组、会话、前台进程组、后台进程组、控制终端、job control 这些unix系统息息相关的概念。通过这些知识我们可以了解到Unix系统中程序的工作模式及与用户的交互方式。我们甚至可以推测从unix系统启动到shell的正常运行及shell中启动其他进程的过程中系统中发生的一些事情。这些对于unix系统底层开发应该是不可或缺的。

 

文章评论

初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
旅行,写作,编程
旅行,写作,编程
如何成为一名黑客
如何成为一名黑客
我是如何打败拖延症的
我是如何打败拖延症的
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
漫画:程序员的工作
漫画:程序员的工作
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
我的丈夫是个程序员
我的丈夫是个程序员
2013年美国开发者薪资调查报告
2013年美国开发者薪资调查报告
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
每天工作4小时的程序员
每天工作4小时的程序员
程序员都该阅读的书
程序员都该阅读的书
总结2014中国互联网十大段子
总结2014中国互联网十大段子
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
2013年中国软件开发者薪资调查报告
2013年中国软件开发者薪资调查报告
编程语言是女人
编程语言是女人
鲜为人知的编程真相
鲜为人知的编程真相
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
老程序员的下场
老程序员的下场
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
那些争议最大的编程观点
那些争议最大的编程观点
为什么程序员都是夜猫子
为什么程序员都是夜猫子
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
 程序员的样子
程序员的样子
程序员必看的十大电影
程序员必看的十大电影
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
一个程序员的时间管理
一个程序员的时间管理
程序员和编码员之间的区别
程序员和编码员之间的区别
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
10个调试和排错的小建议
10个调试和排错的小建议
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
那些性感的让人尖叫的程序员
那些性感的让人尖叫的程序员
Java程序员必看电影
Java程序员必看电影
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有