我要成为嵌入式高手之2月23日Linux高编第八天!!
学习笔记
进程
一、进程基本概念
程序:存放在外存中的一段数据组成的文件
进程:是一个程序动态执行的过程,包括进程的创建、进程的调度、进程的消亡
二、进程相关命令
1、top
动态查看当前系统的所有进程信息(根据CPU占用率排序)
PID:唯一识别进程的ID号(>0)
优先级:Linux系统中数值越低优先级越高(-20~+19),Windows相反
进程状态:
R:运行态/就绪态
S:睡眠态/可唤醒等待
D:不可唤醒等待态
T:暂停态
Z:僵尸态
X:结束态
q退出
2、nice
优先级(NI)默认为0
以指定优先级来运行进程
示例:nice -n 优先级 要执行的进程任务
3、renice
重新设定一个正在运行的进程的优先级
示例:renice -n 优先级 进程PID
4、kill
杀死指定的进程任务
示例:kil -9 进程PID
5、killall
杀死进程名对应的所有进程任务
示例:killall -9 进程名
6、ps -ef
查看当前时刻所有进程的信息
PPID:父进程的ID号
ps -ef | grep a.out
7、pstree
查看进程树关系
8、ps -aux
TTY 查看当前进程依赖于哪个终端
9、./a.out &
将a.out放在后台执行
fg 数字:将第几个程序放在前台执行
10、jobs
查看一个终端下后台执行的任务
三、进程的创建
32bits的操作系统:
有32位地址总线(4字节)
一个进程在运行时,操作系统会为该进程分配0~4G虚拟内存空间,分为文本段、数据段、系统数据段;通过mmu内存映射单元,虚拟地址和物理地址完成映射。
1、操作系统管理的区域
文本段:也成为文本区,存放代码和指令
数据段:也成为数据区,可以细分为①字符串常量区②已初始化静态变量和全局变量区③未初始化静态变量和全局变量区
系统数据段:堆区和栈区
①栈区:1)局部变量存放在栈区
基本8mb:2)未经初始化为随机值
3)代码执行到变量定义时为变量开辟空间
4)当变量的作用域结束时回收空间
5)栈的增长方向,自高向低增长
②堆区:1)程序员手动管理(malloc)
2)malloc才能申请到堆区空间,free才能释放堆区空间
3)增长方向:自低向高
③数据区:1)静态变量、全局变量、字符串常量存放在数据区
2)编译时开辟空间,执行时将该空间加载到内存中
3)未经初始化为0值
4)程序结束回收数据区
④文本区:1)存放代码和指令
2、进程中虚拟内存地址和实际物理内存地址的关系
1、0-4g虚拟内存空间只有一个
2、实际物理地址中每个进程空间是独立的
3、通过mmu内存映射单元,当一个进程执行时,将物理地址中的数据加载到虚拟地址中运行
四、进程的调度
1、常见的调度算法
①先来先执行,后来后执行
②高优先级调度
③时间片轮转调度算法
时间片:CPU在一个任务中的运行时间成为一个时间片
④多级队列反馈的调度算法
⑤负载均衡的调度算法
2、宏观串行,微观并行
3、进程的状态:
R 运行态(占用CPU资源)、就绪态(随时准备调度)
S 睡眠态/可唤醒等待态
D 不可唤醒等待态(不能被打断/切换的任务)
T 暂停态(程序运行暂停住了,不占用CPU资源)
Z 僵尸态(进程代码执行完了,空间未被回收)
X 结束态(都执行完毕,空间也被回收完)
五、进程相关函数接口
1、fork
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
功能:创建一个子进程,新创建的进程称为原来进程的子进程,原来的进程称为父进程
返回值:
成功:子进程返回0;父进程返回子进程的PID
失败:失败返回-1;
父进程调用fork创建子进程,子进程拷贝父进程的文本段,数据段,系统数据段
2、getpid
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
功能:获得调用这个进程的pid号
3、getppid
pid_t getppid(void);
功能:获得调用进程的父进程的pid
#include "head.h"int main(void)
{pid_t pid;pid = fork();if (pid == 0){printf("This is Child Process! PID:%d PPID:%d\n", getpid(), getppid());}else if (pid > 0){printf("This is Parent Process! PID:%d Child 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;pid1 = fork();pid_t pid2;if (-1 == pid1){perror("fail to fork1");return -1;}if (pid1 == 0){printf("First Child Process! PID1:%d PPID:%d\n", getpid(), getppid());}else if (pid1 > 0){pid2 = fork();if (pid2 == -1){perror("fail to fork2");return -1;}if (pid2 == 0){printf("Second Child Process! PID2:%d PPID:%d\n", getpid(), getppid());}else if (pid2 > 0){printf("Parent Process! PID:%d PID1:%d PID2:%d\n", getpid(), pid1, pid2);}}while (1){}return 0;
}
4、exit
#include <stdlib.h>
void exit(int status);
功能:让进程结束、刷新缓存区
参数:status:进程结束的状态
返回值:缺省
exit在主函数中使用和return效果一致
#include "head.h"int main(void)
{printf("hello world!");exit(0);printf("how are you");return 0;
}
5、_exit
#include <unistd.h>
void _exit(int status);
功能:直接让进程结束,不刷新缓存区
参数:status进程结束的状态
返回值:缺省
#include "head.h"int main(void)
{printf("hello world!");_exit(0);printf("how are you");return 0;
}
六、进程的消亡
1、僵尸进程:
进程代码执行结束,但是空间代码没有被回收
2、如何避免产生僵尸态?
1)让父进程先结束
2)让父进程回收子进程空间
3、孤儿进程:
进程的父进程先结束,此时该进程成为孤儿进程,此时被系统进程收养(1995)进程在结束时会被系统进程回收进程空间
4、wait
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
功能:回收子进程空间,会阻塞,有同步功能
参数:wstatus 存放子进程结束状态空间的首地址
返回值:成功返回回收到的子进程的pid,失败返回-1;