day25 进程
概念
是程序的一次执行过程,是调度和资源分配的独立单元,是资源分配的最小单位
进程和程序的区别
进程:是动态的,在内存上,包含创建、调度和消亡
程序:是静态的,在硬盘上
CPU的调度机制
时间片轮转机制:cpu以ms级速度在多个进程之间来回切换
进程的五态图
阻塞态不能直接回到运行态!!!
进程的标识
一个终端打开时,会有一个会话id,其包含一个前台进程组,多个后台进程组,一个进程组包含多个进程
pid: process id 进程id
ppid: parent process id 父进程id
pgid: process group id 进程组id
SID:session id 会话id
三个特殊进程号
0:indel进程,操作系统的引导进程
1:init进程,初始化进程,收养孤儿进程
2:kthread进程,用户进程,线程之间调度
shell指令
ps -ef 查看每个进程
ps -aux 查看进程的内存的使用情况
ps -ajx 打印进程树
ps -ajx | grep a.out 查找a.out进程,进程树的形式输出
|: 管道符,上一个指令的输出作为下一个指令的输入
grep a.out: 查找a.out进程
pidof 进程名 查看指定进程id号
进程的状态
D 不可中断的休眠态(usually IO)R 运行态(on run queue)S 可中断的休眠T 挂起态t bug调制状态W 分页X 死亡态 (should never be seen)Z 僵尸For BSD formats and when the stat keyword is used,additional characters may be displayed:< 高优先级 (对其他用户不友好)N 第优先级(对其他用户友好)L 将页面锁定在内存s 会话领导者l 多线程+ 运行在前端
进程的内存
操作系统 | 指针 | 虚拟内存大小 |
32 | 4字节 | 2^32--->4G |
63 | 8字节 | 2^48--->256TB 虚拟内存没那么多,取48位 |
内核与用户空间划分3:1
堆和栈的区别
0.申请和释放 存放内容 地址方向 空间大小 碎片化程度
1.堆区空间用户申请和释放,栈区空间计算机自动申请和释放
2.堆区存放malloc申请的空间,栈区存储局部变量
3.地址方向不同:堆区从低到高,栈从高到低
4.堆区空间2G-3G,栈区空间8M
5.堆区碎片化严重,栈区基本没有碎片化
堆栈溢出
空间不足,递归层数较多时,计算机不断申请栈区空间,此时可能会空间不足
内存泄漏
堆区申请的空间已经不使用了,但是未释放
进程相关函数
frok
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
功能:创建子进程,子进程拷贝父进程的用户空间
参数:无
返回值:成功父进程返回子进程的pid号
子进程返回0
失败返回-1,更新errno
用户空间:堆区,栈区,静态区,缓冲区,文件描述符
内核空间共享(光标:打开文件一次,子进程拷贝父进程,光标共享)
n次fork后:2^n个进程
父子进程执行顺序不固定,sleep()放弃cpu资源
写实拷贝
子进程拷贝父进程的用户空间
不发生数据改变时,父子进程共享同一物理内存页
当一个进程发生数据改变时,内核会触发缺页异常,此时才会分配新的物理页,复制内容,解除写保护,此后,父子进程才各自拥有独立的副本。
作用:高效性,节省资源
getpid | getppid
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
pid_t getppid(void);
功能:顾名思义,获取调用者pid或ppid
参数:无
返回值:成功返回调用者的pid或ppid 不会失败
exit
#include <stdlib.h>
void exit(int status);
功能:退出进程,并把退出状态值返回给父进程
库函数调用,刷新缓冲区
参数:int status 退出状态值,人为规定0表示正常退出,一般写0
返回值:无
status 退出状态值,一般正常退出为0,异常退出为非0
_exit
#include <unistd.h>
void _exit(int status);
功能:退出进程,并把退出状态值返回给父进程
系统调用,不刷新缓冲区
参数:int status 退出状态值,人为规定0表示正常退出,一般写0
返回值:无
wait
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
功能:阻塞函数,等待任意子进程退出,回收子进程资源(回收僵尸资源)接收exit的退出状态值
参数:int *wstatus 该指针指向内存中存储exit的退出状态值
NULL 不接收exit的退出状态值
返回值:
成功返回接收子进程的pid,失败返回-1,更新errno
WEXITSTATUS(wstatus) 计算退出状态值的 (status&0xff00)>>8
waitpid
pid_t waitpid(pid_t pid, int *wstatus, int options);
功能:阻塞函数(可非阻塞),等待任意子进程退出,回收子进程资源(回收僵尸资源)接收exit的退出状态值
参数:
pid_t pid
<-1 等待进程组id等于pid绝对值的进程组下的任意子进程 -1 等待当前进程的任意子进程结束 等价于wait 0 等待当前进程组的任意子进程结束 >0 等待回收指定子进程 int *wstatus 该指针指向内存中存储exit的退出状态值
NULL 不接收exit的退出状态值
int options 0:阻塞
WNOHANG:设置为非阻塞
返回值:
成功返回接收子进程的pid,失败返回-1,更新errno
#include <25061head.h>
int main(int argc, const char *argv[])
{ pid_t pid=fork();if(pid>0){int status; //定于退出状态值pid_t ret=wait(&status); //ret接收返回值printf("%d pid::%d ret::%d status=%d\n",__LINE__,getpid(),ret,WEXITSTATUS(status)); //status为0是因为此处为信号中断,低八位为0,宏函数返回值为0if(WIFEXITED(status)) //是否为异常退出{printf("正常退出\n");}else{printf("异常退出\n");printf("%d\n",status); //139printf("%d\n",WEXITSTATUS(status)); //0}int sig;sig=WTERMSIG(status);printf("%d\n",sig);if(sig=WTERMSIG(status)) //是否为信号中断printf("%d信号中断\n",sig);}else if(pid==0){printf("%d pid::%d \n",__LINE__,getpid());kill(getpid(), SIGSEGV); int *p=NULL;*p=100;exit(7);}else{ERR_MSG("FORK ERROR");}return 0;
}
vfork
同fork 区别:子进程共享父进程的地址空间 子进程先运行,父进程阻塞
宏函数
WIFEXITED(wstatus) | 判断是否是异常退出的,如果正常退出则返回真,否则返回假 |
WEXITSTATUS(wstatus) | 计算退出状态值的 (status&0xff00)>>8 |
WTERMSIG(wstatus) | 判断是否是信号中断的, 如果是信号中断则返回真(信号编号) |
进程扇
#include <25061head.h>
void pid_create(int n)
{for(int i=1;i<=n;i++){pid_t pid =fork();if(pid==0) //子进程{ sleep(i); //确保顺序输出printf("子进程%d pid=%d ppid=%d\n",i,getpid(),getppid());//关闭子进程sleep(n-i+1); //统一时间关闭exit(0);}}
}
int main(int argc, const char *argv[])
{ int n;printf("需要创建几个子进程\n");scanf("%d",&n);pid_create(n);//回收子进程pid_t pid2;while((pid2=wait(NULL))!=-1)printf("pid=%d子进程回收\n",pid2); printf("父进程 pid=%d\n",getpid());return 0;
}
进程链
#include <25061head.h>
void pid_create(int n)
{static int i=1;pid_t pid =fork();if(n==1&&pid==0) //递归出口{printf("子进程%d代 pid=%d 父进程ppid=%d\n",i,getpid(),getppid());exit(0);return ;}if(pid==0) //子进程{ printf("子进程%d代 pid=%d 父进程ppid=%d\n",i++,getpid(),getppid());pid_create(n-1);_exit(0);}else //父进程wait(NULL);//回收子进程 }
int main(int argc, const char *argv[])
{ int n;printf("需要创建几个子进程\n");scanf("%d",&n);printf("父进程 pid=%d\n",getpid());pid_create(n);printf("父进程 pid=%d结束\n",getpid());return 0;
}