进程
目标
- 掌握fork/getpid/getpid/getppid函数的使用
- 熟练掌握ps/kill命令的使用
- 熟练掌握execl/execlp函数的使用
- 说出什么时僵尸进程 什么是孤儿进程
- 熟练掌握wait函数的使用
- 熟练掌握waitpid函数的使用
程序相关概念
什么是程序 ?
编译好的二进制文件 .
什么是进程 ?
运行着的程序. 站在程序员的角度,运行一系列指令的过程. 站在系统角度分配好资源的基本单位.
区别
-
程序占用磁盘,不占用系统资源
-
内存占用系统资源
-
一个程序对应多个进程,一个进程对应一个程序.
-
程序没有生命周期,进程有生命周期.
进程相关函数
fork 创建进程
#include <unistd.h>
pid_t fork(void);
返回值
-
失败返回-1
-
成功两次返回
- 父亲进程返回 子进程id
- 子进程返回0
getpid获取进程id / getppid获取父进程id
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
pid_t getppid(void);
实例
#include<sys/types.h>
#include<unistd.h>
#include<stdio.h>
int main()
{
pid_t id = getpid();
printf("当前进程的id为:%d\n",id);
printf("开始创建进程\n");
pid_t id1 = fork();
if(id1<0){
perror("fork err");
return -1;
}
printf("\n创建进程结束\n");
if(id1 == 0)
{
printf("我是子进程:%d\n",getpid());
pid_t id2 = getppid();
printf("我的父进程:%d\n",id2);
return 0;
}
printf("我是父进程:%d\n",id);
printf("我的子进程:%d\n",id1);
return 0;
}
子进程打印时发现父进程的id为1 因为父进程先死了.
查看进程
ps aux
ps ajx
杀死进程
kill -9 进程id
进程共享
父子进程之间在fork后.有哪些相同不同之处?
刚fork后:
- 父子相同之处:全局变量, data, text, 堆, 栈, 环境变量, 用户id, 宿主目录, 进程工作目录, 信号处理函数…
- 父子不同之处:
- 进程ID
- fork() 返回值
- 进程运行时间
- 闹钟(定时器)
- 未决信号集
似乎子进程复制了父进程0-3G的用户空间, 以及父进程的PCB, 但pid不同. 真的每一个子进程都复制了一份父进程的地址空间?
当然不是, 父子进程遵循读时共享,写时复制的原则. 这样无论执行子进程还是父进程的逻辑都能节省空间开销.
测试,父子进程是否共享变量.
#include<unistd.h>
#include<sys/types.h>
#include<stdio.h>
int main()
{
int a = 100;
pid_t pid = fork();
if(pid < 0)
{
printf("创建子进程失败\n");
return 0;
}
if(pid == 0)
{
printf("子进程a 的地址%p\n",&a);
}
else
{
printf("父进程a 的地址%p\n",&a);
sleep(1);
}
}
exec族函数
#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
实例
#include<unistd.h>
int main()
{
// execl("ls","ls","-l","--color=auto",NULL);
execlp("/bin/ls","ls","-l","--color=auto",NULL);
perror("");
return 0;
}
孤儿进程和僵尸进程
孤儿进程: 父进程死了,子进程被init进程领养.
僵尸进程: 子进程死了,父进程没有回收资源(PCB)
如何回收僵尸进程: 杀死父亲,init 进程领养,负责回收.
回收进程
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
wait
作用: 阻塞等待 回收子进程资源 查看死亡原因
wait
- 成功返回终止的子进程ID
- 失败返回-1
waitpid
- pid
- <-1 -组id
- -1 回收任意
- 0 回收和调用进程id相同组内的子进程
- >0 回收指定的pid
- options
- 0与wait相同,也会阻塞
- WNOHANG 如果当前没有子进程退出,会立刻返回
查看死亡原因
-
正常死亡: WIFEXITED(status)
如果正常死亡 WIFEXITED为真,WEXITSTATUS(status)得到退出状态
-
非正常死亡 WIFSIGNALED(status)
WIFSIGNALED为真WTERMSIG(status)得到第几号信号将其杀死的.
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
pid_t pid = fork();
if(pid == 0)
{
printf("I am child, will die!\n");
sleep(2);
// return 102;
exit(103);
}
else if(pid >0)
{
printf("I am parent, wait for child die\n");
int status;
pid_t wpid = wait(&status);
printf("wait ok, wpid = %d, pid = %d\n",wpid,pid);
if(WIFEXITED(status)){
printf("child exit with %d\n",WEXITSTATUS(status));
}
if(WIFSIGNALED(status)){
printf("child exit with %d\n",WTERMSIG(status));
}
}
return 0;
}