嵌入式学习的第二十七天-进程
2)exit(), c库函数,会执行io库的清理工作,关闭所有的流,以及所有打开的文件。(3)程序执行的过程,包括进程的创建、调度、消亡.c ----> a.out-----> process(pid)(4)子进程复制父进程的0到3g空间和父进程内核中的PCB,但id号不同。6)abort() 不允许应用层调用,若产生严重错误,系统自行调用该函数,关闭进程。killall -9 (发送信息,强制关
一、进程

1.进程的含义
进程是一个程序执行的过程,进程要使用系统的资源,即会去分配内存资源,cpu的调度
pcb 是一个结构体,process control block print circuit board
2.进程和程序的区别
(1)程序:静态 存储在硬盘中代码,数据的集合
(2)进程:动态 存储在内存上
(3)程序执行的过程,包括进程的创建、调度、消亡 .c ----> a.out-----> process(pid)
1)程序是永存,进程是暂时的
2)进程有程序状态的变化,程序没有
3)进程可以并发,程序无并发
4)进程与进程会存在竞争计算机的资源
5)一个程序可以运行多次,变成多个进程 ;一个进程可以运行一个或多个程序
3.内存的分布

0-3G,是进程的空间,3G-4G是内核的空间,虚拟地址
虚拟地址 * 物理内存和虚拟内存的地址 映射表 1page=4k mmu


a.out是ELF的一种形式,a.out里会放ELF、code 、data
stack:栈区 最大不超过8M 存放局部变量、形参、函数的返回地址
map/share:映射区和共享区 只读、将外面的内存空间映射过来,可减少a.out的空间 放标准库,so
heap:堆区、动态存储空间,由程序员使用和申请
data/bss:全局变量、静态变量区、可读可写 ; bass(未初始化的全局变量)
code:代码区、只读

注:面试题

4.进程分类
(1).交互式进程
(2).批处理进程 shell脚本
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char **argv)
{
while (1)
{
printf("$");
char buf[1024] = {0};
fgets(buf, sizeof(buf), stdin);
int len = strlen(buf);
buf[len - 1] = '\0';
if (0 == strcmp(buf, "quit") || strcmp(buf, "exit") == 0)
{
return -1;
}
else
{
char *s[5] = {NULL};
int i = 0;
s[i] = strtok(buf, " ");
while (s[++i] = strtok(NULL, " "))
;
// for(i = 0;i < 5;++i)
// {
// printf("s[%d] = %s\n",i,s[i]);
// }
pid_t pid = fork();
if (pid < 0)
{
perror("fail fork");
return -1;
}
if (pid > 0)
{
wait(NULL);
continue;
}
else if (0 == pid)
{
if(execvp(s[0], s)< 0)
{
perror("execvp fail");
return -1;
}
}
}
}
}

(3).守护进程 :类似杀毒软件,不需要典型输入,自己能运行
5.进程的状态
3个状态,就绪→执行态→阻塞(等待,睡眠)基本操作系统是最大的管家

linux中的状态,运行态,睡眠态,僵尸,暂停态。

6.进程的作用
并发,并行区别(同一时刻同时发生)
eg:while (1) { while (1) { 上下左右 发视频} }
7.进程的调度
进程上下文切换
内核主要功能之一就是完成进程调度, 硬件,bios,io,文件系统,驱动
调度算法: other,idle ,rr,fifo
先来先服务->短任务有限->优先级->多级任务队列->时间片轮转
宏观并行
微观串行

8.查询进程相关命令
(1)ps aux : 查看进程相关信息
- 就绪态、运行态 R
- 睡眠态、等待态
- 可唤醒等待态 S
- 不可唤醒等待态 D
- 停止态 T
- 僵尸态 Z
- 结束态 X
- 多线程程序 L
(2) top:根据CPU占用率查看进程相关信息,类似windows下任务管理器
(3).kill和killall:发送一个信号; kill -l 查看可以发送的信号;
kill -2 (发2号信号) PID 15(通知DID关闭信号)
发送信号+PID对应的进程,默认接收者关闭
killall -9 (发送信息,强制关闭)进程名 发送信号 进程名对应的所有进程

(4)pstree 显示父子关系图
pstree -sp 显示更多信息
pstree -sp[pid] 查看指定的进程的进程数

二、进程相关的函数
1.fork();并发运行
pid_t fork(); 叉子
特性:(1)一次调用,会返回两次。
(2)子进程先运行还是父进程先进程,顺序不确定。
(3)变量不共享。父子之间空间独立,操作互不影响。
(4)子进程复制父进程的0到3g空间和父进程内核中的PCB,但id号不同。
功能:通过该函数可以从当前进程中克隆一个同名新进程。
关系:(1)克隆的进程称为子进程,原有的进程称为 父进程。
(2)子进程是父进程的完全拷贝。子进程大于父进程。
(3)子进程的执行过程是从fork函数之后执行。
(4)子进程与父进程具有相同的代码逻辑。
返回值:int 类型的数字。
在父进程中:成功 返回值是子进程的pid号 >0;失败 返回-1;
在子进程中:成功 返回值 0
失败 无
#include <stdio.h>
#include<string.h>
#include<sys/types.h>
#include <unistd.h>
int main(int argc, char **argv)
{
printf("start...\n");
pid_t ret=fork();
if(ret>0)
{
while (1)
{
printf("father,发送视频\n");
sleep(1);
}
}
else if(0==ret)
{
while(1)
{
printf("child,接受视频\n");
sleep(1);
}
}
else
{
perror("fork");
return 1;
}
return 0;
}
代码结构:
2.getpid
pid_t getpid(void);
功能:获得调用该函数进程的pid
参数:缺省
返回值:进程的pid
3.getppid
pid_t getppid(void);
功能:获得调用该函数进程的父进程pid号
参数:缺省
返回值:返回父进程id号
#include <stdio.h>
#include<string.h>
#include<sys/types.h>
#include <unistd.h>
int a=20;
int main(int argc, char **argv)
{
printf("start...\n");
pid_t ret=fork();
if(ret>0)
{
int i=10;
while (i--)
{
printf("father,发送视频 pid:%d ,ppid:%d a:%d \n",getpid(),getppid(),a);
sleep(1);
}
}
else if(0==ret)
{
int i=10;
a+=10;
while(i--)
{
printf("child,接受视频 pid:%d ,ppid:%d a:%d \n",getpid(),getppid(),a);
sleep(1);
}
}
else
{
perror("fork");
return 1;
}
printf("a is %d pid:%d ,ppid:%d\n",a,getpid(),getppid());
return 0;
}
注: 由此可看出变量不共享


4.父子进程的关系
子进程是父进程的副本。子进程获得父进程数据段,堆,栈,正文段共享。
在fork之后,一般情况那个会先运行,是不确定的。如果非要确定那个要先运行,需要IPC机制,取决于操作系统的调度算法。
调度算法:先来先服务;短作业优先;高优先级;时间片轮转;
区别:1)fork的返回值
2)pid不同
5.父子进程的文件共享问题
情况一:fork之前打开文件 子进程会继承父进程的文件描述符 共用一个offset值

情况二:fork之后打开文件 子进程和父进程各自独立拥有自己的fd 相互之间独立的offset 数据可能形成覆盖

父进程可能被覆盖
三、练习
1.动态生成n个子进程,并打印输出各自进程的pid号
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int n=5;
int i=0;
printf("father: pid:%d ,ppid:%d \n", getpid(), getppid());
for (i=0 ; i < 5; ++i)
{
pid_t ret = fork();
if (ret > 0)
{
continue;
}
else if (0==ret)
{
printf("child: pid:%d ,ppid:%d \n", getpid(), getppid());
break;
}
else
{
perror("fork");
return 1;
}
}
return 0;
}
2.fork()&&fork()||fork();
一共五个进程

3. 设计一个程序,动态生成两个进程,分别向相同的文件中 写入不同的数据,要表明是两个进程同时写入的数据。 父进程1123 186 16:02:10 子进程1124 188 16:02:15

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
int main(void)
{
FILE*fp=fopen("1.txt", "w");
pid_t pid=fork();
if(pid>0)
{
int i=3;
while(i--)
{
int num=rand()%100+20;
time_t tm=time(NULL);
struct tm *tm_info = localtime(&tm);
fprintf(fp,"father %d num:%d %d:%d:%d\n",getpid(),num,tm_info->tm_hour,tm_info->tm_min,tm_info->tm_sec);
fflush(fp);
sleep(3);
}
}
else if(0==pid)
{
int i=2;
while(--i)
{
int num=rand()%100+20;
time_t tm=time(NULL);
struct tm *tm_info = localtime(&tm);
fprintf(fp,"child %d num:%d %d:%d:%d\n",getpid(),num,tm_info->tm_hour,tm_info->tm_min,tm_info->tm_sec);
fflush(fp);
sleep(5);
}
}
else
{
perror("fork");
return 1;
}
fclose(fp);
return 0;
}
补充:
1.ulimit -a 进线程
2. man -k +关键字 模糊搜索
3.time 的两种传参方式

4.grep 查找
面试题:

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐




所有评论(0)