原创 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就万事大吉了。

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
5
关闭 站长推荐上一条 /3 下一条