【学习嵌入式day-24-进程】
·
#include "../head.h"
int main(void)
{
char word[32] = {0}; //存终端输入的单词
char tmpbuff[1096] = {0}; //存文件里的每行内容
char *pret = NULL;
FILE *fp = NULL;
char first_word[32] = {0}; //存第一个单词
char meaning[1024] = {0}; //存释义
//使用strtok时:
char *ptmpword = NULL;
char *pmean = NULL;
//从终端输入单词
printf("请输入单词:\n");
fgets(word, sizeof(word), stdin);
word[strlen(word)-1] = '\0';
//打开目的文件
fp = fopen("dict.txt", "r");
if(NULL == fp)
{
perror("fail to fopen");
return -1;
}
//fgets逐行读目的文件里的内容,找输入的单词
while(1)
{
pret = fgets(tmpbuff, sizeof(tmpbuff), fp);
if(NULL == pret)
{
break;
}
/*
//使用sscanf提取第一个单词和释义
if(2 == sscanf(tmpbuff, "%31s %[^\n]", first_word, meaning))
{
if(strcmp(first_word, word) == 0)
{
printf("%s\n", meaning);
return 1;
}
}
*/
//使用strtok分割单词
ptmpword = strtok(tmpbuff, " ");
if(0 == strcmp(ptmpword, word))
{
pmean = strtok(NULL, "\r");
if(pmean != NULL)
{
while(*pmean == ' ' || *pmean == '\t')
{
pmean++;
}
printf("单词含义:%s\n", pmean);
fclose(fp);
return 1;
}
}
}
printf("未找到该单词\n");
fclose(fp);
return 0;
}
链表是在内存中的,文件是在外存中存储的,内存中加载快
进程
概念
- 进程:是程序动态执行的过程,包括创建、调度、消亡
- 程序:存放在外存中的一段数据的集合
进程的创建
进程空间分布
- 每个进程运行起来后,操作系统开辟0 - 4G虚拟内存空间
- 进程空间:用户空间 + 内核空间(不允许用户访问)
- 用户空间:文本段(文本区) + 数据段(数据区) + 系统数据段(堆区、栈区)
- 文本段:存放代码和指令
- 数据段:字符串常量、已初始化全局变量/静态变量、未初始化全局变量/静态变量
- 系统数据段:堆区(malloc空间:申请大空间)、栈区(局部变量、函数运行:小变量)
- 栈区存放数据特点:
- 未经初始化值为随机值
- 执行到变量定义开辟内存空间
- 超过变量作用域回收变量空间
- 堆区存放数据特点:
- malloc申请堆区空间
- free释放堆区空间
- 避免内存泄漏
- 数据区特点:
- 未经初始化值为0值
- 编译时开辟空间
- 程序结束时回收空间
- 栈区存放数据特点:

虚拟地址和物理地址
虚拟地址
所有能够被用户看到的地址均为虚拟地址,表示用户可以寻址的范围
物理地址
内存存放数据对应的实际硬件物理地址
MMU:内存映射单元
实际地址和物理地址之间的映射 由内存映射单元(MMU)来完成

多进程存储
存储方式
- 多个进程空间在操作系统中存储时,空间是独立的(物理空间地址是独立的)
- 多个进程在操作系统中共用同一个虚拟内存空间(虚拟地址是共享的)
多进程的调度

-
常见的进程调度算法
- 先来先执行,后来后执行
- 高优先级调度算法
- 时间片轮转调度算法
- 多级队列反馈调度算法
- 负载均衡调度算法
- 多进程调度本质
- 宏观并行,微观串行
- 宏观分析:一个CPU同时执行多个进程任务
- 微观分析:一个CPU在多个任务中高速切换保障多任务

进程相关的命令
top(动态查看)

ps -ef(查看当前进程信息)

ps - aux

后台执行进程任务

jobs

fg

nice / renice

kill / killall

进程的状态

进程相关的函数接口
fork

- 子进程拷贝父进程文本段、数据段、系统数据段
- 进程的PID不一样
- fork的返回值不一样,父进程中返回子进程的PID,子进程中返回0
- PID 一定是 > 0
- 子进程返回0
- 父进程的返回值 > 0
- 父子进程空间独立,同一份代码中的变量和数据都会在父子进程中各有一份,父子进程修改自己空间的数据不会影响对方的空间

getpid和getppid
获得自己的PID和获得父进程的PID

#include "../head.h"
int main(void)
{
pid_t pid;
pid = fork();
if(-1 == pid)
{
perror("fail to fork");
return -1;
}
if(0 == pid)
{
printf("我是子进程,PID:%d PPID:%d\n", getpid(), getppid());
}
else if(pid > 0)
{
printf("我是父进程,PID:%d childPID:%d\n", getpid(), pid);
}
printf("hello world\n");
while(1)
{
}
return 0;
}
父进程创建两个子进程
#include "../head.h"
int main(void)
{
pid_t pid;
pid_t pid2;
pid = fork();
if(-1 == pid)
{
perror("fail to fork");
return -1;
}
if(0 == pid)
{
printf("我是子进程1,PID:%d PPID:%d\n", getpid(), getppid());
}
else if(pid > 0)
{
pid2 = fork();
if(-1 == pid2)
{
perror("fail to fork");
return -1;
}
if(0 == pid2)
{
printf("我是子进程2,PID:%d PPID:%d\n", getpid(), getppid());
}
else if(pid2 > 0)
{
printf("我是父进程,PID:%d 子进程1PID:%d 子进程2PID:%d\n", getpid(), pid, pid2);
}
}
printf("hello world\n");
while(1)
{
}
return 0;
}
exit

- 在主函数中调用exit和return功能一样
- return 在函数内部将结束该函数
- exit 在函数内部将结束进程
- exit 会在结束前刷新缓存区
_exit

进程回收
wait(回收子进程空间)

-
wait具有阻塞等待功能,等到有子进程结束才会回收子进程继续向下执行
-
wait 可以实现多父子进程同步
#include "../head.h"
int main(void)
{
pid_t pid;
pid_t ret;
int status;
pid = fork();
if(-1 == pid)
{
perror("fail to fork");
return -1;
}
if(0 == pid)
{
sleep(5);
printf("子进程即将退出\n");
exit(0);
}
else if(pid > 0)
{
ret = wait(NULL);
ret = wait(&status); //传参数知道子进程是什么原因死的
printf("回收到子进程(PID:%d)空间\n", ret);
while (1)
{
}
}
return 0;
}
#include "../head.h"
int main(void)
{
pid_t pid;
pid_t ret;
int status;
pid = fork();
if(-1 == pid)
{
perror("fail to fork");
return -1;
}
if(0 == pid)
{
sleep(5);
printf("子进程即将退出\n");
exit(10);
}
else if(pid > 0)
{
ret = wait(&status); //传参时一般不使用指针,避免操作野指针
printf("回收到子进程(PID:%d)空间\n", ret);
if(WIFEXITED(status))
{
printf("子进程正常结束,退出值为:%d\n", WEXITSTATUS(status));
}
else if(WIFSIGNALED(status))
{
printf("子进程被 %d 号信号杀死\n", WTERMSIG(status));
}
}
return 0;
}
waitpid
#include "../head.h"
int main(void)
{
pid_t pid;
pid_t ret;
int status;
pid = fork();
if (-1 == pid)
{
perror("fail to fork");
return -1;
}
if (0 == pid)
{
sleep(10);
printf("子进程即将退出!\n");
exit(20);
}
else if (pid > 0)
{
// ret = wait(&status);
while (1)
{
ret = waitpid(pid, &status, WNOHANG);
if (ret > 0)
{
break;
}
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;
}
- waitpid 可以用非阻塞回收子进程空间
- waitpid 可以回收指定子进程空间
进程消亡
孤儿进程
父进程先结束,子进程会称为孤儿进程,被Init进程收养
僵尸进程
- 是每个进程结束必然会经历的阶段
- 产生原因:子进程结束后,父进程没有回收 子进程的空间,导致进程执行结束,空间仍然被占用的状态,称为僵尸进程
- 避免:
- 父进程先结束,子进程会成为孤儿进程,孤儿进程被init进程收养,子进程再结束,init进程回收进程空间
- 子进程结束,父进程回收子进程空间,避免产生僵尸进程
更多推荐



所有评论(0)