学习嵌入式第二十八天
文章目录
- 进程和线程
- 1.进程
- 1.基本概念
- 2.进程的创建
- 3.进程相关的函数接口
- 4.进程消亡
- 习题
进程和线程
1.进程
1.基本概念
- 程序:存放在外存中的一段数据的集合
- 进程:是程序动态执行的过程,包括创建,调度和消亡
2.进程的创建
-
进程空间的分布
- 每个进程运行起来后,操作系统开辟0 - 4G的虚拟内存空间
- 进程空间:用户空间+内核空间(不允许用户访问)
- 用户空间:文本段(文本区)+数据段(数据区)+系统数据段(堆区、栈区)
- 文本段:存放代码和指令
- 数据段:字符串常量、已初始化全局变量/静态变量、未初始化全局变量/静态变量
- 数据区存放数据特点:
- 未经初始化值为0值
- 编译时开辟空间
- 程序结束时回收空间
- 系统数据段:堆区(malloc空间)、栈区(局部变量、函数运行)
- 堆区存放数据特点:
- malloc申请堆区空间
- 栈区存放数据特点:
- 未经初始化值为随机值
- 执行到变量定义开辟内存空间
- 超过变量作用域回收变量空间
-
虚拟地址和物理地址
- 虚拟地址
- 所有能被用户看到的地址均为虚拟地址均为虚拟地址,表示用户可以寻址的范围
- 物理地址
- 内存存放数据对应的实际硬件物理地址
- MMU
- 实际地址和物理地址之间的映射由内存映射单元(MMU)完成
- 虚拟地址
-
多进程存储
-
存储方式
-
多个进程空间在操作系统中存储时,空间是独立的(物理地址是独立的)
-
多个进程在操作系统中共用同一个虚拟内存空间(虚拟地址是共享的)
-
-
-
多进程的调度
- 常见的进程调度算法
- 先来先执行,后来后执行
- 高优先级调度算法
- 时间片轮转调度算法
- 多级队列反馈调度算法
- 负载均衡调度算法
- 多进程调度的本质
- 宏观并行,微观串行
- 常见的进程调度算法
-
进程相关命令
-
top
示例:top 功能:根据CPU占用率和内存占用率查看当前所有进程的信息PID:唯一区分进程的ID号 USER:创建者 PR/NI:优先级 VIRT/RES/SHR:资源占用 S:状态 %CPU:CPU占用率 %MEM:内存占用率 TIME+:运行时长 COMMAND:进程命令
-
ps -ef
示例:ps -ef 功能:查看该时刻所有进程信息UID:创建进程用户 PID:进程的ID号 TIME/CMDps -ef | grep 进程名 查找与进程名对应的进程信息
-
ps -aux
示例:ps -aux功能:查看该时刻所有进程的信息USER:创建者 PID:进程的ID号 %CPU:CPU占用率 %MEM:内存占用率 VSZ RSS TTY STAT:进程的状态 START TIME COMMAND
-
后台执行进程任务
示例:./a.out & 功能:后台执行a.out进程
-
jobs
示例:jobs 功能:查看终端下所有后台进程任务
-
fg
示例:fg 编号(通过jobs查看) 功能:后台执行的任务被放到前台执行
-
nice/renice
示例:nice -n 优先级编号 进程名renice -n 优先级编号 进程PID 功能:改变进程的优先级优先级范围:-20~20 数字越小优先级越高
-
kill/killall
示例:kill -编号 进程PIDkillall -编号 进程名功能:杀死进程
-
-
进程的状态
进程状态 标识 含义 就绪态/运行态 R 进程位于CPU任务调度的队列中 可唤醒等待态 S 等待某个资源的到来,资源到来后被唤醒加入调度队列,等待过程可被打断 不可唤醒等待态 D 等待某个资源的到来,资源到来后被唤醒加入调度队列,等待过程不可被打断 停止态 T 用户人为让进程任务暂停等待 僵尸态 Z 进程代码运行结束,空间尚未回收 结束态 X 进程代码运行结束,空间被回收
3.进程相关的函数接口
-
fork
原型:pid_t fork(void); 功能:创建一个新的进程,新的进程称为子进程,调用fork的进程称为父进程 参数:缺省 返回值:父进程中返回子进程的PID子进程中返回0出错返回-1
- 子进程拷贝父进程文本段、数据段、系统数据段
- 父进程与子进程空间独立,同一份代码中的个变量和数据都会在父子进程中各有一份,父子进程修改自己空间的数据不会影响对方
- 进程的PID不一样
- fork的返回值不一样
- PID > 0
-
getpid和getppid
原型:pid_t getpid(void); 功能:获得调用函数进程的PID号原型:pid_t getppid(void); 功能:获得调用函数父进程的PID号
-
exit和_exit
原型:void exit(int status); 功能:结束进程任务并返回进程结束状态 参数:status:进程结束的状态值原型:void _exit(int status); 功能:结束进程任务并返回进程结束状态 参数:status:进程结束的状态值 返回值:
- 在主程序中调用和return功能一致
- return在函数内部将结束该函数
- exit在函数中会结束该进程
- exit会在结束前刷新缓存区
- _exit不会刷新缓存区
-
wait
原型:pid_t wait(int *wstatus) 功能:回收子进程空间 参数:wstatus:存放子进程结束空间的首地址 返回值:成功返回回收到的子进程的PID失败返回-1
- wait具有阻塞等待功能,等到有子进程结束才会回收子进程继续向下执行
4.进程消亡
- 孤儿进程
- 父进程先结束,子进程会变成孤儿进程,被init进程收养
- 僵尸进程
- 每个进程结束必然会经历的阶段
- 产生原因:子进程结束后,父进程没有回收子进程空间,导致进程执行结束,空间依然被占用的状态。
- 避免产生僵尸进程
- 父进程先结束,子进程会成为孤儿进程,孤儿进程被init进程收养,子进程再结束,init进程回收进程空间
- 子进程结束,父进程回收子进程空间,
习题
编写一个程序,将当前系统中所有进程的PID、PPID、Name信息记录到record.txt文件中
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<dirent.h>
#include<math.h>
#include<time.h>
#include<sys/wait.h>int get_allnumdir(struct dirent *pp){char *pstr = NULL;pstr = pp->d_name;while(pstr != NULL && *pstr != '\0'){if(*pstr < '0' || *pstr > '9'){return -1;}pstr++;}return 1;
}
void get_information(FILE *fp1,char *name,char *pid,char *ppid){char buff[100] = {0};char *str = NULL;rewind(fp1);while(fgets(buff,sizeof(buff),fp1) != NULL){str = strtok(buff,"\t");if(0 == strcmp(str,"Name:")){str = strtok(NULL,"\n");strcpy(name,str);}else if(0 == strcmp(str,"Pid:")){str = strtok(NULL,"\n");strcpy(pid,str);}else if(0 == strcmp(str,"PPid:")){str = strtok(NULL,"\n");strcpy(ppid,str);} }
}int main(void){FILE *fp = NULL;FILE *fp1 = NULL;DIR *dir = NULL;struct dirent *pp = NULL;char tmpbuff[4096] = {0};char ppid[10] = {0};char pid[10] = {0};char name[100] = {0};fp = fopen("record.txt","w");if(NULL == fp){perror("fail to fopen");return -1;}dir = opendir("/proc");if(NULL == dir){perror("fail to opendir");return -1;}while(1){tmpbuff[0] = '\0';memset(name, 0, sizeof(name));memset(pid, 0, sizeof(pid));memset(ppid, 0, sizeof(ppid));pp = readdir(dir);if(NULL == pp)break;if(get_allnumdir(pp) == 1){sprintf(tmpbuff,"/proc/%s/status",pp->d_name);fp1 = fopen(tmpbuff,"r");if(NULL == fp1){continue;}get_information(fp1,name,pid,ppid);fprintf(fp,"Name: %s\n",name);fprintf(fp,"PID: %s\n",pid);fprintf(fp,"PPID: %s\n",ppid);fclose(fp1);}}closedir(dir);fclose(fp);return 0;
}