多进程点滴

多进程点滴
复制进程映像fork函数:
   内核进程表会创建新的进程表项,该进程表项的很多属性与原进程相同,子进程继承父进程的数据(代码区、静态数据区、堆区和栈区)(利用写时复制技术)。父进程打开的文件描述符默认情况下在子进程中是打开的,并且应用计数加1;不仅如此,父进程的用户根目录、用户当前工作目录等变量的引用计数也加1。不过,父进程设置的信号处理函数不再对子进程有效。
   父进程必须谨慎地管理其分配的文件描述符和堆内存等系统资源,否则子进程可能复制这些资源,从而使系统的可用资源急剧下降,进而影响服务器的性能。
替换进程映像exec系列函数:
   exec系列函数不会关闭原进程打开的文件描述符,除非原进程的文件描述符设置了类似SOCK_CLOEXEC的属性。
僵尸(子)进程wait/waitpid函数:
   父进程需要跟踪子进程的退出状态。因此,在子进程结束运行之后内核进程表不会立即释放子进程的进程表项,以满足父进程后续对子进程退出信息的查询。1)当子进程结束运行、父进程读取其结束状态之前,子进程处于僵尸态;2)父进程结束或异常终止,而子进程继续执行,此时init进程接管该子进程,并等待其结束,此时子进程处于僵尸态。
   当waitpid函数的pid参数取值-1时waitpid等效于wait函数。当options参数取值为WNOHANG宏时waitpid调用是非阻塞的,此时如果pid指定的目标子进程没有结束或异常终止则waitpid立即返回0;如果目标子进程确实正常退出了则waitpid返回该子进程的PID。只有 在事件已经发生的情况下执行非阻塞调用才能提高程序的效率,因此当父进程捕获到SIGCHLD信号后在信号处理函数中调用waitpid以彻底结束一个子进程。
进程间通信:管道(匿名/命名)、信号、socket、System V IPC(信号量、消息队列和共享内存)、POSIX IPC(信号量、消息队列、共享内存)。
   信号量概念依据于PV原语(P:进入临界区;V:退出临界区)。信号量取值可以是任意自然数,但最常用、最简单是二进制信号量。
   System V IPC与POSIX IPC区别是前者需要一个全局唯一的键值标识IPC对象,并且IPC_RMID宏表示移除IPC对象。
   与O_CREAT|O_EXCL标志调用open函数排他性创建文件相同,使用IPC_CREAT|IPC_EXCL调用semget排他性创建信号量集。使用特殊键值IPC_PRIVATE,无论该信号量是否存在,semget都将创建一个新的信号量。
   子进程只拥有一个执行线程,它是调用fork的那个线程的完整复制,并且子进程自动继承父进程互斥锁(条件变量与之类似)的状态。这就引出了一个问题:子进程可能不清楚从父进程继承来的互斥锁的具体状态。因此pthread线程库提供了专门函数pthread_atfork以确保fork调用后父子进程都拥有一个清楚的锁状态。
   每个线程都可以独立地设置信号掩码,由于进程的所有线程共享该进程的信号,所以线程库将根据信号掩码决定把信号发送给哪个具体线程(当然可以通过调用pthread_kill明确地把信号发送给一个指定线程)。因此我们需要定义一个专门的线程来处理所有的信号(通过两个步骤实现:1>在主线程创建其他子线程之前调用pthread_sigmask设置好信号掩码,所有新创建的子线程都将自动继承这个信号掩码;2>指定其中一个线程调用sigwait函数来等待信号并处理信号(此时不需要为该信号设置信号处理函数了))。

你可能感兴趣的:(多进程点滴)