原创
Linux高级编程 - 进程(Processes)
2010-12-29 21:35
1659
5
5
分类:
工程师职场
ALP(Advanced Linux Programming) Chapter 3 进程(Processes)
- 什么叫进程?一个程序运行的一个实例称为一个进程(A RUNNING INSTANCE OF A PROGRAM IS CALLED A PROCESS)
3.1进程的基本操作
- 进程的ID号
- 每个进程有一个唯一的ID号,叫做pid(Process ID)。
- 基本上每个进程都有一个父进程(单性繁殖),父进程的id是ppid (Parent Process ID)。当然也有例外,不然你告诉我最早的那个进程怎么来的?
- ID号的类型是pid_t,pid和ppid可以分别通过系统函数getpid()和getppid()来得到。
- ps命令可以输出当前活动的进程,这个命令为了和Unix的命令相匹配,有很多的options。例如-e表示输出所有,-u表示输出指定user的进程,等等。
- 一个进程死了?无法退出了?如果你是windows用户,你一定会怀念Ctrl+Alt+Del。OK,其实在Linux下也很简单,用ps查到进程的PID,然后kill -9 PID,搞定。这里的9事实上是SIGKILL,也就是表示中止进程的signal。
3.2 进程的创建
- 进程的创建有两种方法。第一种,简单!便宜没好货,所以这种方法也低效,不安全。第二种复杂,但是灵活度高,高效,还安全。
- 第一种,system。system函数事实上只是创建一个当前shell的子进程,然后在shell中执行你指定的程序。所以它的安全度和灵活度都受到当前shell的限制。
- 第二种,fork+exec的组合。fork的任务就是copy当前的进程,生成一个完全一样的进程。exec的任务就是执行你指定的程序,exec之前进程中的所有数据都被清空,就像一个全新的进程一样。
- 进程调度,也就是哪个进程先执行,哪个进程后执行。在父进程和子进程直接没有必然的先后执行顺序。不过我们可以给进程指定优先级,优先级越高的越有可能先被执行(注意,是有可能,不是一定),所有进程的默认优先级都是0。
- 用nice命令加上-n option来指定进程优先级。这里的option可以为负数,那意味着你降低了这个进程的优先级,降低优先级的操作需要有root权限。
- 用renice命令给一个已经被nice过的进程重新指定优先级。
3.3 Signal
- Signal是一种Unix的机制,可以给进程发送一个signal来达到通讯以及控制的目的。(本来想把signal翻成信号,可惜信号量这个词被OS里面的semaphore给占用了,为了避免混淆,干脆不翻了)
- 我们可以把signal理解成为发送给进程的一个特别的消息,进程在收到signal之后,必须停下当前的代码马上处理之(类似于中断)。有三种处理方式:
- 如果进程没有声明要处理该signal,则采取该signal的默认处理方式,通常是结束程序。
- 进程可以声明忽略该signal(使用sigaction函数)
- 进程可以声明处理该signal(使用sigaction函数),并提供一个signal处理函数。
- 虽然非常非常少见,但是有可能程序在执行signal处理函数的时候被另一个signal所打断,因此signal处理函数必须是线程安全的。
- Signal的例子:
- SIGBUS:BUS出错
- SIGSEGV:段错误(segmentation violation)
- SIGPFE:浮点指针异常
- SIGINT:中断signal,通常用户可以在程序执行过程中用Ctrl+C来向程序发送这个signal
- SIGTERM:中止signal,通常结束一个程序,除非程序忽略该signal
- SIGKILL:中止signal,总是结束一个程序,程序无法忽略该signal
3.4 进程的终结
- 一个进程可以有很多钟终结的方式,例如正常终结,被上面提到的各种signal终结。我们可以用kill函数来给一个进程发送signal,如kill (child_pid, SIGTERM)。
- 由于系统在调度父进程和子进程的时候没有一定的顺序,但有些时候父进程又需要等待子进程结束后再继续。怎么办?
- 最简单的方法是使用wait函数,该函数会阻塞当前的进程,直到它的一个子进程结束(或者有错误发生)。
- wait函数会返回子进程的exit code。
- Linux还有其他更灵活的wait函数,例如waitpid,wait3,wait4等
- 假设父进程没有调用wait等待子进程,但此时子进程已经结束了。由于子进程必须等待父进程来收集它的结束信息,因此它不能够就这么完全结束了,它成为了一种新的形态:僵尸进程(zombie process,这么翻觉得别扭,还是继续用zombie吧)
- 在子进程成为zombie process后,如果父进程调用了wait,则子进程从zombie形态退出,完全结束。
- 如果父进程没有调用wait而直接结束,则zombie子进程会被Init进程接管(就是那个pid为1的著名进程),Init将做为zombie子进程的新父进程,负责收尾工作,子进程结束。
- 很显然,我想大部分的programmer都不想spawn一个子进程之后,父进程马上什么都不能做,只能傻傻的被阻塞在wait中等待子进程结束。万幸,我们可以通过signal来完成父进程对子进程的异步等待,子进程结束之后会向父进程发送一个SIGCHLD的signal,该 signal的默认操作是什么事都不做,现在我们只需在这个signal的处理函数里面调用wait就万事大吉了。
关闭
站长推荐
/3
文章评论(0条评论)
登录后参与讨论