进程基本概念
一、进程:
程序:存放在外存中的一段数据组成的文件
进程:是一个程序动态执行的过程,包括进程的创建、进程的调度、进程的消亡
二、进程相关的命令
1.top
动态查看当前系统中所有的进程信息(根据CPU占用率排序)
PID:唯一识别进程的ID号(>0)
优先级:linux系统中数据低,优先级高(-20~19) Windows系统和中数值越高,优先级越高
进程状态:
R 运形态/就绪态
S 睡眠态/可唤醒等待态
D 不可唤醒等待态
T 暂停态
Z 僵尸态
X 结束态
q退出查看进程
2.nice
以指定优先级开运行进程
示例:
nice -n 优先级 要执行的集成任务
renice:重新设定一个正在运行的进程的优先级
示例:
renice -n 优先级 进程PID
3.kill
杀死指定进程任务
示例:
kill -9 进程PID
killall
杀死名对应的所有进程任务
示例:
killall -9 进程名
4.ps -ef
查看当前时刻所有的进程信息
PPID:父进程ID号
示例:
ps -ef | grep a.out
5.pstree
查看进程树关系
6.ps -aux
查看当前时刻的进程信息
7../a.out &
就是将a.out任务放在后台执行
8.jobs
查看一个终端下后台执行的所有任务
9.fg
将后台任务放到前台执行
示例:
fg 编号
三、进程的创建
32bits操作系统下
一个进程在运行时,操作系统会将进程分分配为0-4G虚拟内存空间,分为文本段、数据段、系统数据段。
文本段:
也被称呼为文本区,存放代码和指令
数据段:
也称为数据区、可以细分为:
1)字符串常量区
2)为初始化的全局变量/静态变量
3)已初始化的全局白能量/静态变量
系统数据段:包含堆区和栈区
四、进程中虚拟地址和物理地址大的关系
1.0-4G虚拟内存空间只有一个
2.实际物理地址中每个进程空独立
3.通过MMU内存映射单元,单一个进程执行时,将物理地址之中的数据加载到虚拟地址中运行
五、进程的调度
1.常见的的调度算法
1)先来先执行,后来后执行
2)高优先级调度算法
3)时间片轮转调度算法
4)多级队列反馈调度算法
5)负载均衡调度算法
时间片:CPU在一个任务中的运行时间称为一个时间片
2.宏观并行,微观串行
3.进程状态:
R 运行态(CPU正在执行)、就绪态(等待调度)
S 睡眠态/可唤醒等状态
D 不可唤醒等待态(不能被打断/切换的任务)
T 暂停态(程序运行在此停住,需手动执行)
Z 僵尸态(代码已经结束,空间未回收)
X 结束态(代码结束,空间回收)
六、进程相关的函数接口
1.进程的创建:fork
功能:
创建一个子进程,新创建按的进程被称为原来进程的子进程,原来的的进程被称为新进程的父进程
参数:void
返回值:
成功子进程返回0
父进程返回子进程的PID
失败返回-1
解释:父进程调用fork创建子进程,子进程拷贝父进程文本段、数据段、系统数据段
getpid (当前进程)
pid_t getpid(void);
功能:获得调用进程的PID号
getppid (父进程)
pid_t getppid(void);
功能:获得调用进程的PPID
#include "head.h"
int main(void)
{
pid_t pid;
pid = fork();
if (pid == -1)
{
perror("fail to fork");
return -1;
}
if (pid == 0)
{
printf("子进程 PID=%d,PPID=%d\n",getpid(),getppid());
}else if (pid > 0)
{
printf("父进程 PID=%d,chinl PID=%d\n",getpid(),pid);
}
printf("hello world\n");
while(1)
{
}
return 0;
}
练习:
创建一个父进程的两个子进程,自进程中打印自己的PID和父进程的PID;父进程中打印自己的PID和两个子进程的PID
#include "head.h"
int main(void)
{
pid_t pid1;
pid_t pid2;
pid1 = fork();
if (pid1 == -1)
{
perror("fail to fork");
return -1;
}
if (pid1 == 0)
{
printf("子进程1 PID=%d PPID=%d\n",getpid(),getppid());
}else if (pid1 > 0)
{
pid2 = fork();
if (pid2 == -1)
{
perror("fail to fork");
return -1;
}
if (pid2 == 0)
{
printf("子进程2 PID1=%d PPID=%d\n",getpid(),getppid());
}else if (pid2 > 0)
{
printf("父进程 PID=%d chinl PID1=%d chinl PID2=%d\n",getpid(),pid1,pid2);
}
}
while(1)
{
}
return 0;
}
linux@ubuntu:~/c/软件编程/进程$ ./a.out
父进程 PID=26204 chinl PID1=26205 chinl PID2=26206
子进程1 PID=26205 PPID=26204
子进程2 PID1=26206 PPID=26204
判断:打印出来Num的值
#include "head.h"
int main(void)
{
pid_t pid;
int Num = 0;
pid = fork();
if (-1 == pid)
{
perror("fail to fork");
return -1;
}
if (0 == pid)
{
Num = 100;
}
else if (pid > 0)
{
sleep(5);
printf("Num = %d\n", Num);
}
return 0;
}
判断:打印数组中的元素
#include "head.h"
char tmpbuff[1024] = {0};
int main(void)
{
pid_t pid;
pid = fork();
if (-1 == pid)
{
perror("fail to fork");
return -1;
}
if (0 == pid)
{
strcpy(tmpbuff, "hello world");
}
else if (pid > 0)
{
sleep(5);
printf("tmpbuff = %s\n", tmpbuff);
}
return 0;
}
结果:都打印不出来
解释:当执行到fork,创建出子进程,此时子进程将父进程的所有的文本段、数据段、系统数据段全部拷贝过来,此时两个进程的实际物理空间独立,所以互不影响。
2.结束进程:exit
void exit(int status);
功能:
让进程结束
参数:
status:进程结束的参数
返回值:缺省
exit在主函数中使用和return效果一致
exit会刷新缓存区
_exit
void _exit(int status);
功能:
让进程直接结束 但是不会刷新缓存区
参数:
status:进程结束的状态
返回值:缺省
#include "head.h"
void Fun(void)
{
exit(0);
}
int main(void)
{
printf("hello world");
Fun();
printf("how are you");
return 0;
}
linux@ubuntu:~/c/软件编程/进程$ ./a.out
hello worllinux@ubuntu:~/c/软件编程/进程$
3.回收进程空间:wait
pid_t wait(int *wstatus);
功能:
回收子进程空间
参数:
wstatus:存放子进程结束状态空间的首地址
返回值:
成功返回回收到的子进程PID
失败返回-1
1)wait函数具有阻塞功能
2)wait函数具有同步功能
WIFEXITED(wstatus)
进程是否正常退出
WEXITSTATUS(wstatus)
进程结束状态值
WIFSIGNALED(wstatus)
进程是否被信号杀死
WTERMSIG(wstatus)
获得杀死进程的信号编号
#include "head.h"
int main(void)
{
pid_t pid;
pid_t ret;
int wstatus;
pid = fork();
if (-1 == pid)
{
perror("fail to fork");
return -1;
}
if (0 == pid)
{
printf("子进程开始执行: PID:%d PPID:%d\n", getpid(), getppid());
printf("子进程即将结束!\n");
sleep(10);
exit(10);
}
else if (pid > 0)
{
printf("父进程开始执行: PID:%d\n", getpid());
ret = wait(&wstatus);
if (-1 == ret)
{
perror("fail to wait");
return -1;
}
printf("回收到 %d 子进程空间\n", ret);
if (WIFEXITED(wstatus))
{
printf("正常结束,值为 %d\n", WEXITSTATUS(wstatus));
}
else if (WIFSIGNALED(wstatus))
{
printf("被 %d 号信号杀死\n", WTERMSIG(wstatus));
}
}
return 0;
}
linux@ubuntu:~/c/软件编程/进程$ ./a.out
父进程开始执行: PID:26557
子进程开始执行: PID:26558 PPID:26557
子进程即将结束!
回收到 26558 子进程空间
正常结束,值为 10
七、进程的消亡
1.僵尸态:
进程代码结束,空间 没有被回收,称为僵尸进程
2.如何避免产生僵尸进程?
1)让父进程先结束
2)让父进程回收子进程空间
3.孤儿进程:
进程的父进程先结束,此时该进程成为孤儿进程,被系统进程收养,进程在结束时,会被系统进程回收进程空间