一、Linux进程
程序:死的。只占用磁盘空间。 ——剧本。
进程;活的。运行起来的程序。占用内存、cpu等系统资源。 ——戏。
PCB进程控制块:
进程id
文件描述符表
进程状态:初始态、就绪态、运行态、挂起态、终止态。
进程工作目录位置
*umask掩码
信号相关信息资源。
用户id和组id
二、fork函数
fork函数:
pid_t fork(void)
创建子进程。父子进程各自返回。父进程返回子进程pid。子进程返回 0。
getpid(); 获取当前进程id。
getppid(); 获取当前进程的父进程id。
循环创建N个子进程模型:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
int main(int argc, char *argv[])
{
int i;
pid_t pid;
for (i = 0; i < 5; i++) {
if (fork() == 0) // 循环期间, 子进程不 fork
break;
}
if (5 == i) { // 父进程, 从 表达式 2 跳出
sleep(5);
printf("I'm parent \n");
} else { // 子进程, 从 break 跳出
sleep(i);
printf("I'm %dth child\n", i+1);
}
return 0;
}
父子进程相同:
刚fork后。data段、text段、堆、栈、环境变量、全局变量、宿主目录位置、进程工作目录位置、信号处理方式。
父子进程不同:
进程id、返回值、各自的父进程、进程创建时间、闹钟、未决信号集。
父子进程共享:
读时共享、写时复制。———————— 全局变量。
1. 文件描述符 2. mmap映射区。
三、exec函数族
使进程执行某一程序。成功无返回值,失败返回 -1。
int execlp(const char *file, const char *arg, ...); 借助 PATH 环境变量找寻待执行程序
参1: 程序名
参2: argv0
参3: argv1
...: argvN
哨兵:NULL
int execl(const char *path, const char *arg, ...); 自己指定待执行程序路径。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(void)
{
pid_t pid;
pid = fork();
if (pid == -1 ) {
perror("fork");
exit(1);
} else if (pid > 0) {
printf("I'm parent pid = %d, parentID = %d\n", getpid(), getppid());
} else if (pid == 0) {
sleep(3);
printf("i am child\n");
execl("/bin/ls", "ls", "-l", NULL);
perror("exec");
exit(1);
}
printf("-------finish...%d\n", getpid());
return 0;
}
四、僵尸进程和孤儿进程
孤儿进程:
父进程先于子进终止,子进程沦为“孤儿进程”,会被 init 进程领养。
僵尸进程:
子进程终止,父进程尚未对子进程进行回收,在此期间,子进程为“僵尸进程”。 kill 对其无效。
五、进程回收
5.1 wait函数
wait函数:回收子进程退出资源, 阻塞回收任意一个。
pid_t wait(int *status)
参数:(传出) 回收进程的状态。
返回值:成功: 回收进程的pid
失败: -1, errno
函数作用1: 阻塞等待子进程退出
函数作用2: 清理子进程残留在内核的 pcb 资源
函数作用3: 通过传出参数,得到子进程结束状态
获取子进程正常终止值:
WIFEXITED(status) --》 为真 --》调用 WEXITSTATUS(status) --》 得到 子进程 退出值。
获取导致子进程异常终止信号:
WIFSIGNALED(status) --》 为真 --》调用 WTERMSIG(status) --》 得到 导致子进程异常终止的信号编号。
示例程序:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
int main(void)
{
pid_t pid, wpid;
int status;
pid = fork();
if(pid == -1){
perror("fork error");
exit(1);
} else if(pid == 0){ //son
printf("I'm process child, pid = %d\n", getpid());
sleep(1);
exit(10);
} else {
wpid = wait(&status); //传出参数
if(WIFEXITED(status)){ //正常退出
printf("I'm parent, The child process "
"%d exit normally\n", wpid);
printf("return value:%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) { //异常退出
printf("The child process exit abnormally, "
"killed by signal %d\n", WTERMSIG(status));
//获取信号编号
} else {
printf("other...\n");
}
}
return 0;
}
5.2 waitpid函数
waitpid函数:指定某一个进程进行回收。可以设置非阻塞。waitpid(-1, &status, 0) == wait(&status);
pid_t waitpid(pid_t pid, int *status, int options)
参数:
pid:指定回收某一个子进程pid
> 0: 待回收的子进程pid
-1:任意子进程
0:同组的子进程。
status:(传出) 回收进程的状态。
options:WNOHANG 指定回收方式为,非阻塞。
返回值:
> 0 : 表成功回收的子进程 pid
0 : 函数调用时, 参3 指定了WNOHANG, 并且,没有子进程结束。
-1: 失败。errno
示例程序:
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
pid_t pid;
pid = fork();
if (pid < 0) {
perror("fork failed");
exit(1);
}
if (pid == 0) {
int i;
for (i = 3; i > 0; i--) {
printf("This is the child\n");
sleep(1);
}
exit(34);
} else {
int stat_val;
waitpid(pid, &stat_val, 0); //阻塞
if (WIFEXITED(stat_val))
printf("Child exited with code %d\n", WEXITSTATUS(stat_val));
else if (WIFSIGNALED(stat_val))
printf("Child terminated abnormally, signal %d\n", WTERMSIG(stat_val));
}
return 0;
}
总结:
wait、waitpid 一次调用,回收一个子进程。
想回收多个。while 。