APUE:进程环境,进程控制,进程关系
C程序布局
在文件中:正文段(机器指令) text,初始化数据段 data,未初始化数据段 bss
在内存中:(低地址)text,data,bss,堆(向高地址生长)……(向低地址生长)栈,命令行参数,环境变量(高地址)
环境变量
char *getenv (const char *__name); int putenv (char *__string); int setenv (const char *__name, const char *__value, int __replace); int unsetenv (const char *__name); int clearenv (void);
退出程序
int atexit (void (*__func) (void)); void exit (int __status); void _Exit (int __status); void _exit (int __status);
setjmp()和longjmp()
int _setjmp (struct __jmp_buf_tag __env[1]); void longjmp (struct __jmp_buf_tag __env[1], int __val); jmp_buf jmpbuffer; int main() { volatile int volaval; // 内存变量,寄存器变量无法恢复上下文 switch(setjmp(jmpbuffer)) { // label_0 case 0: // label_1 longjmp(jmpbuffer, 1); // goto label_0, label_2 case 1: // label_2 longjmp(jmpbuffer, 2); // goto label_0, label_3 case 2: // label_3 // ... } }
进程标识
// 进程 ID __pid_t getpid (void); // 父进程 ID __pid_t getppid (void); // 实际用户 ID __uid_t getuid (void); // root 设置实际用户 ID、有效用户 ID、保存的设置用户 ID;非 root 只设置有效用户 ID 且 uid 必须等于实际用户 ID 或保存的设置用户 ID int setuid (__uid_t __uid); // 实际组 ID __gid_t getgid (void); // 类似 setuid() int setgid (__gid_t __gid); // 有效用户 ID __uid_t geteuid (void); // 设置有效用户 ID,非 root 时 uid 必须等于实际用户 ID 或保存的设置用户 ID int seteuid (__uid_t __uid); // 有效组 ID __gid_t getegid (void); // 类似 seteuid() int setegid (__gid_t __gid); // 交换实际用户 ID 和有效用户 ID int setreuid (__uid_t __ruid, __uid_t __euid); // 类似 setreuid() int setregid (__gid_t __rgid, __gid_t __egid); // 进程组 ID __pid_t getpgrp (void); __pid_t getpgid (__pid_t __pid); // 将 pid 加入 pgid,如果相等表示创建新的进程组 int setpgid (__pid_t __pid, __pid_t __pgid);
fork()后子进程继承父进程的:
- 打开文件(文件描述符,相当于直接dup,共享同一偏移量)
- 实际用户ID、实际组ID、有效用户ID、有效组ID、附属组ID
- 进程组ID、会话ID
- 控制终端
- 设置用户ID标志和设置组ID标志
- 当前目录和根目录
- 文件模式创建屏蔽字(umask)
- 信号屏蔽和安排
- 对任意打开文件描述符的的close-on-exec标志
- 环境
- 连接的共享存储段
- 存储映像
- 资源限制
exec()系列函数
int execl (const char *__path, const char *__arg, ... /*, NULL */); int execle (const char *__path, const char *__arg, ... /*, NULL, char *const __envp[] */); int execlp (const char *__file, const char *__arg, ... /*, NULL */); int execv (const char *__path, char *const __argv[]); int execve (const char *__path, char *const __argv[], char *const __envp[]); int execvp (const char *__file, char *const __argv[]); int fexecve (int __fd, char *const __argv[], char *const __envp[]);
wait()系列函数
#define WIFEXITED(status) #define WIFSIGNALED(status) #define WIFSTOPPED(status) #define WIFCONTINUED(status) __pid_t wait (__WAIT_STATUS __stat_loc); __pid_t waitpid (__pid_t __pid, int *__stat_loc, int __options /* = WNOHANG */); int waitid (idtype_t __idtype /* = P_PID or P_PGID or P_ALL */, __id_t __id, siginfo_t *__infop, int __options); __pid_t wait3 (__WAIT_STATUS __stat_loc, int __options, struct rusage * __usage); __pid_t wait4 (__pid_t __pid, __WAIT_STATUS __stat_loc, int __options, struct rusage *__usage);
进程调度(优先级)、进程时间
int nice (int __inc); int getpriority (__priority_which_t __which, id_t __who); int setpriority (__priority_which_t __which, id_t __who, int __prio); clock_t times (struct tms *__buffer);
解释器文件
假设解释器文件内容是:
#! /bin/awk -f
...
调用时:
# myscript arg1 arg2
实际调用:
# /bin/awk -f myscript arg1 arg2
进程组织
- 会话包含多个进程组,进程组包含多个进程
- 一个会话有一个控制终端(比如 shell),有一个前台进程组,多个后台进程组,只有前台进程组才能接收到 CTRL+C 之类的信号
- 终端输入和产生的信号会向前台进程组中所有进程发送
- 作业与会话类似,shell 中用 & 启动进程时,实际是就是后台进程组,用 | 管道连接时,这条命令中所有进程属于同一个进程组