第八章 异常控制流(下)

进程控制:

每个进程都有一个唯一的整数进程PID。

进程一般可认为处于以下三种状态:运行、停止、终止;

 

父进程可以通过调用fork函数创建一个新的运行的子进程。父进程和新创建的子进程之间最大的区别在于它们有不同的pid。

fork函数具有以下几个特点:

1、调用一次,返回两次。一次返回给父进程,一次返回到新创建的子进程。

2、并发执行。父进程和子进程是并发运行的独立进程。

3、相同但是独立的地址空间。父进程和子进程都有自己独立的地址空间。

4、共享文件。子进程继承了父进程所有的打开文件。

 

回收子进程:

当一个进程由于某个原因终止时,内核并不是立即将它从系统中清除。相反,进程被保持在一种已终止的状态中,直到被它的父进程回收。当父进程回收已终止的子进程时,内核将子进程的退出状态传递给父进程,然后抛弃已终止的进程。从此时开始,该进程就不存在了。一个终止了但还未被回收的进程被称为僵死进程。

 

如果一个父进程终止了,内核会安排init进程去回收它们。init进程的pid为1,是在系统启动时由内核创建的,它不会终止,是所有进程的祖先。

 

 

信号:

信号:通知进程系统中发生了一个某种类型的事件。

每个信号类型都对应于某种系统事件。信号提供了一种机制,通知用户进程发生了这些异常。比如,如果一个进程试图除以0,那么内核会发送给它一个SIGFPE的信号。

 

传送一个信号到目的进程分两个步骤:

1、发送信号。内核通过更新目的进程上下文中的某个状态,发送一个信号给目的进程。发送信号可以由如下两种原因:

     1)内核检测到一个系统事件,比如除零错误或终止进程。

     2)一个进程调用了kill函数

发送信号有几种形式:

     1)用/bin/kill程序发送信号

     2)从键盘发送信号

     3)用kill函数发送信号

     4)用alarm函数发送信号

2、接收信号:当目的进程被内核强迫以某种方式对信号的发送做出反应时,它就接收了信号。进程可以忽略这个信号,终止或者通过执行一个信号处理程序的用户层函数捕获这个信号。

      一个发出而没有被接收的信号被称为待处理信号。如果一个进程有一个类型k的待处理信号,那么任何接下来发送到这个进程的类型为k的信号都不会排队等待,它们只是被简单的丢弃。

 

举一个例子:

发送三个SIGCHLD信号给父进程,但是其中只有两个信号被接收了。why?

解释如下:当第一个信号到达时,父进程接收并捕获到第一个信号。当处理程序还在处理第一个信号时,第二个信号就传送并添加到了待处理信号集合里。然而,因为SIGCHLD信号被SIGCHLD处理程序阻塞了,所以第二个信号就不会被接收。此后不久,就在处理程序还在处理第一个信号时,第三个信号到达了。因为已经有了一个待处理的SIGCHLD信号,第三个SIGCHLD信号就会被丢弃。这也就是为何最后父进程这边只有两个信号被接收了。

 

因此,需牢记:不可以用信号来对其他进程中发生的事件计数。

 

非本地跳转:

非本地跳转有两个重要应用:

1、允许从一个深层嵌套的函数调用中立即返回,通常是由检测到某个错误情况引起的。如果在一个深层嵌套的函数调用中发现了一个错误情况,我们可以使用非本地跳转直接返回到一个普通的本地化的错误处理程序,而不是费力的解开调用栈。

2、使一个信号处理程序分支到一个特殊的代码位置,而不是返回到被信号到达中断了的指令的位置。

 

posted @ 2019-01-06 18:26  凌晨六点半  阅读(163)  评论(0编辑  收藏  举报