一、进程的含义
进程:是操作系统进行资源分配的最小单位。程序动态执行的过程,包括创建、调度、消亡。每启动一个进程,操作系统就会为它分配一块独立的内存空间。每个进程占有一块独立的内存空间,不同的进程不存在共享空间。
二、进程创建出来的空间和其特点
①文本段(文本区)
代码、指令
②数据段(数据区)
字符串常量,未初始化静态变量/全局变量,已初始化静态变量/全局变量
③系统数据段
堆区:程序员手动管理malloc申请,free释放
栈区:操作系统管理
三、进程的命令
①top
根据CPU占用率动态查看进程信息(按q退出)
②ps -ef
查看当前时刻所有进程的信息
③ps -aux
查看当前时刻进程的信息
④pstree
查看进程关系
⑤kill -9 PID
杀死PID对应的进程
1.创建一个正在运行的进程
2.使用ps -ef查看该进程的的PID
例子中运行的PID为25679
3.在终端输入输入kill -9 25679
4.结果:
⑥killall -9 进程名:
杀死进程名对应的所有进程
eg: killaill -9 xxx.c
四、进程调度的方式
1.宏观并行,微观串行
CPU处理事情很快,表面看起来像是一起进行的,实际上这边执行一下,那边再去执行一下
2.内核进程的调度算法
先来后到
高优先级调度算法
时间片轮转调度算法(时间片指的是CPU在某段任务执行的一段时间)
多级队列反馈调度算法
负载均衡调度算法
五、进程的状态
1.五状态模型
运行态、就绪态、阻塞态、新建态、退出态
2.七状态模型
R( Running):运行态,就绪态. 这里的R对应模型中的等待状态/运行状态
S (Sleeping):睡眠状态,可唤醒等待态.对应模型中的阻塞状态,他必须等待事件。
D(Disk sleep):深度睡眠状态,不可唤醒等待态。是因为受到内核指示而停用的睡眠进程,外部信号无法唤醒它们,只能有内核来亲自唤醒
T(Topped):暂停状态。进程特意停止运行的状态,比如调试器暂停来进行调试操作的时候。
t(tracing stop):它本来不是一个进程的状态,就是用来区分处在暂停状态的进程,看它是否是被调试的进程还是常规的暂停。
Z(Zombie):僵尸状态。代码执行结束,空间没有被回收
六、进程相关的函数接口
创建头文件
#ifndef __HEAD_H__//防止头文件被重复定义
#define __HEAD_H__//防止头文件被重复定义
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#endif //防止头文件被重复定义
1.fork
①函数原型:pid_t fork(void);
②功能:创建一个子进程
③参数:缺省
⑤返回值:成功在父进程中返回子进程PID,子进程中返回0 ,失败返回-1
#include "head.h"
int main(int argc, char const *argv[])
{
pid_t pid;
pid = fork( );
if(-1 == pid)
{
perror("fail to fork");
return -1;
}
if(0 == pid)
{
printf("我是子进程\n");
}
if(0 < pid)
{
printf("我是父进程\n");
}
return 0;
}
运行结果:
2.getpid
①函数原型:pid_t getpid(void);
②功能:获得调用该函数的进程的PID
③参数:缺省
#include "head.h"
int main(int argc, char const *argv[])
{
pid_t pid;
pid = fork( );
if(-1 == pid)
{
perror("fail to fork");
return -1;
}
if(0 == pid)
{
printf("我是子进程PID = %d",getpid());
}
if(0 < pid)
{
printf("我是父进程PID=%d 我的子进程PID= %d\n",getpid(),pid);
}
return 0;
}
输出结果:
3.getppid
①函数原型:pid_t getppid(void);
②功能:获得调用该函数父进程的PID
③参数:缺省
#include "head.h"
int main(int argc, char const *argv[])
{
pid_t pid;
pid = fork( );
if(-1 == pid)
{
perror("fail to fork");
return -1;
}
if(0 == pid)
{
printf("我是子进程PID = %d 我的父进程PID=%d\n",getpid(),getppid());
}
if(0 < pid)
{
printf("我是父进程PID=%d 我的子进程PID= %d\n",getpid(),pid);
}
return 0;
}
输出结果:
4.exit
①函数原型:void exit(int status);
②功能:进程退出
③参数:status:进程结束的状态
⑤返回值:缺省
#include "head.h"
int main(int argc, char const *argv[])
{
printf("hello world\n");//有没有/n,hello world都可以输出
exit(0);
printf("how are you\n");
return 0;
}
输出结果:只输出上面的hello world ,因为exit已经将进程结束
5._exit
①函数原型:void _exit(int status);
②功能:直接使进程停止运行,清除其使用的内存空间,并清除其在内核的各种数据结构。
③参数:status:进程结束的状态
⑤返回值:缺省
_exit() —— 直接结束进程进入到内核中
exit() —— 清理I/O缓冲区后再退出进程
#include "head.h"
int main(int argc, char const *argv[])
{
printf("hello world");//注意:这里没有\n,如果添加\n是可以输出来的
_exit(0);
printf("how are you\n");
return 0;
}
输出结果:什么都没有输出
6.exec函数族
①函数原型:
extern char **environ;
int execl(const char *path, const char *arg, ...
/* (char *) NULL */);
int execlp(const char *file, const char *arg, ...
/* (char *) NULL */);利用进程空间执行一个系统命令
int execle(const char *path, const char *arg, ...
/*, (char *) NULL, char * const envp[] */);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],
char *const envp[]);
②功能:利用进程空间执行一段新的代码
l:参数以列表形式传递
p:在系统路径下查找文件
e:执行新代码时,更新环境变量
v:参数以指针数组形式传递
⑤返回值:失败返回-1
7.getenv
①函数原型:char *getenv(const char *name);
②功能:获得环境变量name对应的值
③参数:name:环境变量名
⑤返回值:成功返回环境变量对应的值,失败返回NULL
8.setenv
①函数原型:int setenv(const char *name, const char *value, int overwrite);
②功能:设置环境变量的值
③参数:
name:环境变量名
value:环境变量的值
overwrite:
0值:如果变量名存在不会替换旧值
非0值 :如果变量名存在会替换旧值
⑤返回值:成功返回0 ,失败返回-1
9.system
①函数原型: int system(const char *command);
②功能:执行一条command shell命令 (minishell中可以用到)
#include "head.h"
int main(int argc, char const *argv[])
{
char ch[4096] = {0};
gets(ch);
system(ch);
return 0;
}
输出结果:
七、进程的消亡
僵尸进程
①父进程先结束,子进程会成为孤儿进程,被系统进程收养,子进程再结束,被系统进程回收空间。
②父进程在进程结束时回收子进程空间
wait
wait具有阻塞功能
①函数原型:pid_t wait(int *wstatus);
②功能:回收子进程空间
③参数:wstatus:存放子进程结束状态空间首地址
④返回值:成功返回回收到子进程的ID,失败返回-1
⑤作用:回收子进程空间,具有同步功能
WIFEXITED(wstatus):判断是否正常结束
WEXITSTATUS(wstatus):获得正常结束时返回的值
WIFSIGNALED(wstatus):判断是否被信号杀死(eg:kill -9)
WTERMSIG(wstatus):获得杀死进程任务的信号编号
1.正常结束:
#include "head.h"
int main(int argc, char const *argv[])
{
pid_t pid;
pid_t ret;
int status;
pid = fork();
if(-1 == pid)
{
perror("fail to fork");
return -1;
}
if(0 == pid)
{
printf("子进程:PID%d,PPID%d\n",getpid(),getppid());
sleep(5);//让子进程睡5s
printf("子进程睡醒了\n");
exit(1);
}
else if (pid > 0)
{
printf("父进程 PID:%d\n", getpid());
ret = wait(&status);
if (WIFEXITED(status))
{
printf("是否为正常死亡%d\n", WEXITSTATUS(status));
}
else if (WIFSIGNALED(status))
{
printf("杀死他的信号为:%d\n", WTERMSIG(status));
}
}
return 0;
}
输出结果:(正常死亡结果为1)
2.被信号杀死:
#include "head.h"
int main(int argc, char const *argv[])
{
pid_t pid;
pid_t ret;
int status;
pid = fork();
if(-1 == pid)
{
perror("fail to fork");
return -1;
}
if(0 == pid)
{
printf("子进程:PID%d,PPID%d\n",getpid(),getppid());
sleep(15);//让子进程睡15
printf("子进程睡醒了\n");
exit(1);
}
else if (pid > 0)
{
printf("父进程 PID:%d\n", getpid());
ret = wait(&status);
if (WIFEXITED(status))
{
printf("是否为正常死亡%d\n", WEXITSTATUS(status));
}
else if (WIFSIGNALED(status))
{
printf("杀死他的信号为:%d\n", WTERMSIG(status));
}
}
return 0;
}
输注结果:
3.waitpid
wait(NULL) 等价于 waitpid(-1, NULL, 0)
①函数原型:pid_t waitpid(pid_t pid, int *wstatus, int options);
②功能:回收子进程空间
③参数:
pid:想要回收的子进程空间对应的PID(-1回收任意一个子进程空间)
wstatus:存放进程状态空间首地址
options:
0:阻塞回收子进程空间
WNOHANG:非阻塞回收子进程空间
④返回值:成功返回回收到的子进程空间,失败返回-1 ,非阻塞形式没有回收到子进程空间返回0
#include "head.h"
int main(int argc, char const *argv[])
{
pid_t pid;
pid_t ret;
int status;
pid = fork();
if (-1 == pid)
{
perror("fail to fork");
return -1;
}
if (0 == pid)
{
printf("子进程开始执行: PID:%d, PPID:%d\n", getpid(), getppid());
sleep(5);
printf("子进程即将退出!\n");
exit(0);
}
else if (pid > 0)
{
printf("父进程开始执行: PID:%d\n", getpid());
while ((ret = waitpid(pid, &status, WNOHANG)) == 0)
{
printf("子进程还没结束,我先干会别的!\n");
sleep(1);
}
printf("回收到子进程(PID:%d)空间\n", ret);
if (WIFEXITED(status))
{
printf("子进程正常结束,值为:%d\n", WEXITSTATUS(status));
}
else if (WIFSIGNALED(status))
{
printf("子进程被 %d 信号杀死\n", WTERMSIG(status));
}
}
return 0;
}
输出结果: