linux系统编程-进程
进程
进程:
程序:死的。只占用磁盘空间。 ——剧本。
进程;活的。运行起来的程序。占用内存、cpu等系统资源。 ——戏。
PCB进程控制块:
- 进程id
- 文件描述符表
- 进程状态: 初始态、就绪态、运行态、挂起态、终止态。
- 进程工作目录位置
- *umask掩码
- 信号相关信息资源。
- 用户id和组id
CPU和MMU
中央处理器(CPU)
内存管理单元MMU
进程状态
fork函数:
pid_t fork(void)
创建子进程。父子进程各自返回。父进程返回子进程pid。 子进程返回 0.
getpid(); //获取进程pid
getppid(); //获取父进程pid
循环创建N个子进程
创建子进程后、父子进程都会接着fork()函数继续执行。
循环创建N个子进程模型。 每个子进程标识自己的身份。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int i;
for ( i = 0; i < 5; i++){
if (fork() == 0)
break;
}
if (i == 5){
sleep(5);
printf("i am parent \n");
}else{
sleep(i);
printf("i am %dth child \n",i+1);
}
return 0;
}
父子进程
父子进程相同:
刚fork后。 data段、text段、堆、栈、环境变量、全局变量、宿主目录位置、进程工作目录位置、信号处理方式
父子进程不同:
进程id、返回值、各自的父进程、进程创建时间、闹钟、未决信号集
父子进程共享:
读时共享、写时复制。———————— 全局变量。
- 文件描述符 2. mmap映射区。
gdb调试:
设置父进程调试路径:set follow-fork-mode parent (默认)
设置子进程调试路径:set follow-fork-mode child
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, ...); 自己指定待执行程序路径。
int execvp();
ps ajx --> pid ppid gid sid
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int ret = fork();
if (ret == 0){
int fd1 = open("test.txt",O_RDWR|O_CREAT,0666);
dup2(fd1,STDOUT_FILENO);
execlp("ps","ps","aux",NULL);
}else{
sleep(2);
printf("i am parent \n");
}
return 0;
}
回收子进程
孤儿进程:
父进程先于子进终止,子进程沦为“孤儿进程”,会被 init 进程领养。
僵尸进程:
子进程终止,父进程尚未对子进程进行回收,在此期间,子进程为“僵尸进程”。 kill 对其无效。
wait函数
wait函数: 回收子进程退出资源, 阻塞回收任意一个。
pid_t wait(int *status)
参数:(传出) 回收进程的状态。
返回值:成功: 回收进程的pid
失败: -1, errno
函数作用1: 阻塞等待子进程退出
函数作用2: 清理子进程残留在内核的 pcb 资源
函数作用3: 通过传出参数,得到子进程结束状态
获取子进程正常终止值:
WIFEXITED(status) --》 为真 --》调用 WEXITSTATUS(status) --》 得到 子进程 退出值。
获取导致子进程异常终止信号:
WIFSIGNALED(status) --》 为真 --》调用 WTERMSIG(status) --》 得到 导致子进程异常终止的信号编号。
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
回收子进程
wait:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
pid_t pid , wpid;
int status;
pid = fork();
if (pid == 0){
printf("i am child ,pid = %d ,going to sleep 10s \n",getpid());
sleep(10);
printf("---------------child die ---------\n");
return 73;
}else if (pid > 0){
wpid = wait(&status);
if(wpid == -1){
perror("wait error");
exit(1);
}
if (WIFEXITED(status)){ //为真 子进程正常退出
printf("child exit code : %d \n",WEXITSTATUS(status));
}else if (WIFSIGNALED(status)){ //为真 子进程被信号终止
printf("child exit signal : %d \n",WTERMSIG(status));
}
printf("parent wait finish : %d \n",wpid);
}
return 0;
}
waitpid:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <dirent.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int i;
pid_t pid ,wpid;
for ( i = 0; i < 5; i++){
if (fork() == 0)
break;
}
if (i == 5){
// sleep(5);
// while ((wpid = waitpid(-1,NULL,WNOHANG)) != -1)
// {
// if (wpid > 0 ){
// printf("wait child finish : %d \n",wpid);
// }else{
// sleep(1);
// }
// }
while ((wpid = waitpid(-1,NULL,0)) != -1)
{
printf("wait child finish : %d \n",wpid);
}
}else{
sleep(i);
printf("i am %dth child my pid is %d \n",i+1,getpid());
}
return 0;
}
总结:
- wait、waitpid 一次调用,回收一个子进程。
- 想回收多个。while
License:
CC BY 4.0