APUE学习笔记——进程控制
进程标识
每个进程都有一个非负整型表示的唯一进程ID。
- ID为0的进程通常是调度进程,常常被称为
交换进程(swapper)。该进程是内核的一部分,它并不执行任何磁盘上的程序,因此被称为系统进程。 - 进程ID为1的通常是
init进程,在自举过程结束时由内核调用。init进程决不会终止。它是一个普通的用户进程,但它以超级用户特权运行。 - 进程ID2是
页守护进程(page daemon),此进程负责支持虚拟存储器系统的分页操作。
1 |
|
函数fork
1 |
|
由fork创建的新进程被称为子进程(child process)。
两次返回的区别是子进程的返回值是0,而父进程的返回值则是新建子进程的进程ID。
子进程和父进程继续执行fork调用之后的指令。子进程是父进程的副本。父进程和子进程共享正文段。
一般来说,fork之后是父进程先执行还是子进程先执行是不确定的。
在重定向父进程的标准输出时,子进程的标准输出也被重定向。
子进程和父进程共享一个文件偏移量。
函数vfork
父进程和子进程共享数据段,并且先保诚子进程先运行,只有当子进程调用exec或exit后父进程才可能被调用运行。
调用vfork()后,子程序要么_exit(),要么调用exec(),否则都是未定义行为(UB)
函数exit
5种正常终止方式:
- 在
main函数内执行return语句。 - 调用
exit函数。 - 调用
_exit或_Exit函数。 - 进程的最后一个线程在其启动例程中执行
return语句。 - 进程的最后一个线程调用
pthread_exit函数。
3种异常终止:
- 调用
abort。 - 当进程接收到某些信号时。
- 最后一个线程对“取消”(cancellation)请求作出响应。
对于父进程已经终止的所有进程,它们的父进程都改为init进程,我们称为这些进程由init进程收养。
在UNIX术语中,一个已经终止、但是其父进程尚未对其进行善后处理(获取终止子进程的有关信息、释放它仍占用的资源)的进程被称为僵死进程(zombie)。
函数wait和waitpid
当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号。
如果其所有子进程都还在运行,则阻塞。
如果一个子进程终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回。
如果没有任何子进程,则立即出错返回。
1
2
3
4
5
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid, int *statloc, int options);
/* 两个函数返回值:若成功,返回进程ID;若出错,返回0或-1 */在一个子进程终止前,
wait使其调用者阻塞,而waitpid有一选项,可使调用者不阻塞。waitpid并不等待在其调用之后的第一个终止子进程,可以控制它所等待的进程。
这两个函数的参数statloc是一个整型指针。如果statloc不是一个空指针,则终止进程的终止状态就存放在它所指向的单元内。
| 宏 | 说明 |
|---|---|
| WIFEXITED(status) | 若为正常正常终止子进程返回的状态,则为真。对于这种情况可执行WIFEXITED(status),获取子进程传送给exit或_exit参数的低8位 |
| WIFSIGNALED(status) | 若为异常终止子进程返回的状态,则为真(接到一个不捕捉的信号)。对于这种情况,可执行WIFSIGNALED(status),则为真(接到一个不捕捉的信号)。对于这种情况,可执行()WTERMSIG(status),获取使子进程终止的信号编号。另外,有些实现(非Single UNIX Specification)定义宏WCOREDUMP(status),若已产生终止进程core文件,则它返回真 |
| WIFSTOPPED(status) | 若为当前暂停子进程的返回的状态,则为真。对于这种情况,可执行WSTOPSIG(status),获取使子进程暂停的信号编号 |
| WIFCONTINUED(status) | 若在作业控制暂停后已经继续的子进程返回了状态,则为真 |
waitpid函数中pid参数的作用解释如下:
- pid == -1 等待任一子进程。此种情况下,
wait和waitpid等效。 - pid > 0 等待进程ID与pid相等的子进程。
- pid == 0 等待组ID等于调用进程组ID的任一子进程。
- pid < -1 等待组ID等于pid绝对值的任一子进程。
| options常量 | 说明 |
|---|---|
| WCONTINUED | 若实现支持罪业控制,那么由pid制定的任一子进程在停止后已经继续,但其状态尚未报告,则返回其状态 |
| WNOHANG | 若由pid指定的子进程并不是立即可用的,则waitpid不阻塞,此时其返回值为0 |
| WUNTRACED | 若某实现支持作业控制,而由pid指定的任一子进程已处于停止状态,并且其状态由停止以来还没报告过,则返回其状态。WIFSTOPPED宏确定返回值是否对应于一个停止的子进程。 |
函数waittid
1 |
|
| idtype常量 | 说明 |
|---|---|
| P_PID | 等待一特定进程:id包含要等待子进程的进程ID |
| P_PGID | 等待一特定进程组中的任一子进程:id包含要等待子进程的进程组ID |
| P_ALL | 等待任一子进程:忽略id |
| options常量 | 说明 |
|---|---|
| WCONTINUED | 等待一进程,它以前曾被停止,此后又已继续,但其状态尚未报告 |
| WEXITED | 等待已退出的进程 |
| WNOHANG | 如无可用的子进程推出状态,立即返回而非阻塞 |
| WNOWAIT | 不破坏子进程退出状态。该子进程退出状态可由后续的wait、waitid或waitpid调用取得 |
| WSTOPPED | 等待一进程,它已经停止,但其状态尚未报告 |
函数wait3和wait4
1 |
|
函数exec
调用exec并不创建新进程,所以前后的进程ID并没有改变。exec只是用磁盘上的一个新程序替换了当前进程的正文段、数据段、堆栈和栈段。
1 |
|
当filename作为参数时:
- 如果
filename中包含/,则将其设为路径名; - 否则就按
PATH环境变量,在她所指定的各目录搜寻可执行文件。
execl,execle,execlp(结尾带l)要在可变参数结尾添加(char *)0。
execlp,execvp(结尾带p)表示第一个参数path不用输入完整路径,只有给出命令名即可,它会在环境变量PATH当中查找命令。
execv,execvp(不带l)表示命令所需的参数以char *arg[]形式给出且arg最后一个元素必须是NULL。
更改用户ID和更改组ID
可以用setuid函数设置实际用户ID和有效用户ID;可以用setgid函数设置实际组ID和有效组ID。
1 |
|
若进程拥有超级用户权限,则setuid函数将实际用户ID、有效用户ID以及保存的设置用户ID设置为uid;
若进程没有超级用户权限,但是uid等于实际用户ID或保存的设置用户ID,则
setuid只将有效用户ID设置为uid。不更改实际用户ID和保存的设置用户ID;若以上两个条件都不满足,则
errno设置为EPERM,并返回-1.只有超级用户进程可以更改实际用户ID;
仅当对程序文件设置了设置用户ID位时,
exec函数才设置有效用户ID;保存的设置用户ID是由
ecec复制有效用户ID而得到的。
函数setreuid和setregid
功能是交换实际用户ID和有效用户ID
1 |
|
如若其中任一参数的值为-1,则表示相应的ID应当保持不变。
函数seteuid和setegid
类似于setuid和setgid,但只更改有效用户ID和有效组ID。
1 |
|
函数system
1 |
|
如果cmdstring是一个空指针,则仅当命令程序可用时,system返回非0值,这一特征可以确定在一个给定的操作系统上是否支持system函数。
fork失败或者waitpid返回处EINTR之外的出错,则system返回-1,并且设置errno以指示错误类型。- 如果
exec失败,则返回值如同shell执行了exit(127)一样。 - 否则所有3个函数(
fork、exec和waitpid)都成功,那么system的返回值是shell的终止状态,其格式已在waitpid中说明。
进程会计(process accounting)
1 | typedef u_short comp_t; /* 3-bit base 8 exponent; 13-bit fraction */ |
- 我们不能获取永远不终止的进程的会计记录;
- 在会计文件记录的顺序对应于进程终止的顺序,而不是它们启动的顺序;
- 会计记录对应于进程而不是程序。
exec并不创建一个新的会计记录,但相应记录中的命令名称改变了,AFORK标志被清除。
用户标识
得到运行该程序的用户的登录名,当有多个用户名对应着一个用户ID时,通常返回用户登录时用的用户名。
1 |
|
进程调度
进程可以通过调整nice值选择以最低优先级运行,只有特权进程允许提高调度权限。nice值的大小在0(2*NZERO)-1之间,有些实现支持02NZERO。nice值越小,优先级越高*。
1 |
|
getpriority函数可以像nice函数那样用户获取进程的nice值,但是getpriority还可以获取一组相关进程的nice值。
1 |
|
setpriority函数可以用于为进程、进程组和属于特定用户ID的所有进程设置优先级。
1 |
|
进程时间
times函数获得它自己以及已终止子进程的墙上时钟时间、用户CPU时间和系统CPU时间。
1 |
|
1 | struct tms { |