进程的创建
系统调用fork()允许一个进程创建一个新进程,子进程获得父进程的栈、数据段、堆和执行文本段的拷贝
-
#include <unistd.h>
-
pid_t fork(void);
-
/* in parent: returns process ID of child on success, or -1 on error; in successfully created child: always returns 0*/
大部分现代UNIX实现采用两种计数来避免浪费内存:
1. 将每一个进程的代码段标记为只读,是父子进程可以共享同一代码段
2. 对于父进程的数据段、堆段、栈段当中的各页,内核采用写时复制(copy-on-write)计数来处理
为了子进程立即执行exec()的程序而专门设计的vfork()
-
#include <unistd.h>
-
pid_t vfork(void);
-
/* in parent: returns process id of child on success, or -1 on error; in successfully created child: always returns 0*/
vfork()因为如下两个特性而更具效率:
1. 无需为子进程复制虚拟内存页或页表。相反,子进程共享父进程的内存,直至其成功执行了exec()或是调用_exit()退出。
2. 在子进程调用exec()或_exit()之前,将暂停执行父进程
进程的终止:
系统调用:
-
#include <unistd.h>
-
void _exit(int status);
-
#include <stdlib.h>
-
void exit(int status);
其中exit()会执行以下动作:
1. 调用退出处理程序(通过atexit()和on_exit()注册的函数),其执行顺序与注册顺序相反
2. 刷新stdio流缓冲区
3. 使用由status提供的值执行_exit()系统调用
进程终止的细节
无论进程是否正常终止,都会发生如下动作:
1. 关闭所有打开文件描述符、目录流信息、目录描述符,以及(字符集)转换描述符
2. 作为文件描述符关闭的后果之一,将释放该进程所持有的任何文件锁
3. 分离(detach)任何已连接的System V共享内存段,且对应于各段的shm_nattch计数器值将减1
4. 进程为每个System V信号量所设置的semadj值将会被加到信号量值中
5. 如果该进程是一个管理终端的管理进程,那么系统会向该终端前台进程组中的每个进程发送SIGHUP信号,接着终端会与会话(session)脱离
6. 将关闭该进程打开的任何POSIX有名信号量,类似于调用sem_close()
7. 将关闭该进程打开的任何POSIX消息队列,类似于调用mq_close()
8. 作为进程退出的后果之一,如果某进程组称为孤儿,且该组中存在任何已停止进程,则组中所有进程都将受到SIGHUP信号,随之为SIGCONT信号
9. 移除该进程通过mlock()或mlockall()所创建的任何内存锁
10. 取消该进程调用mmap()所创建的任何内存映射
退出处理程序:
如果程序直接调用_exit()或因信号而异常终止,则不会调用退出处理程序
-
#include <stdlib.h>
-
int atexit(void (*func)(void));
-
/*returns 0 on success, or nonzero on error*/
一旦有任一退出处理程序无法返回,那么就不会再调用剩余的处理程序
阅读(1499) | 评论(0) | 转发(0) |