计算机系统相关(嵌入式)

大端和小端

在大端系统中,最高有效位存储在低地址内存中,最低有效位存储在高地址中。

例如,0x123456在内存中的存储方式
大端模式:

  低地址 -----> 高地址
  0x12 | 0x34 | 0x56 

小端模式:

  低地址 -----> 高地址(低存低更符合直觉)
  0x56 | 0x34 | 0x12 

Why?

  1. 一开始是由于不同架构的CPU处理多个字节数据的顺序不一样,比如x86的是小段模式,KEIL C51是大端模式。但是后来互联网流行,TCP/IP协议规定为大端模式,为了跨平台通信,还专门出了网络字节序和主机字节序之间的转换接口(ntohs、htons、ntohl、htonl)

  2. 大小端模式各有优势:小端模式强制转换类型时不需要调整字节内容,直接截取低字节即可(也更符合直觉);大端模式由于符号位为第一个字节,很方便判断正负。

如何判断大小端?

 BOOL IsBigEndian()
 {
 	short a = 0x1234;
 	char b = *(char*)&a;   //强制类型转化
 	if(0x12 == b)
 	{
 	    return TRUE;
 	}
 	
	return FALSE;
  }

32和64位系统

  • 处理数据的能力:32位计算机的CPU一次最多能处理32位数据。64位计算机一次能处理64位数据。这和寄存器位数有关
  • 支持的内存不同(寻址能力不同):32位的系统许多支持4G的内存,而64位则可以支持上百G的内存。
  • 架构不同:不同位处理意味着指令集等要做重新设计,一般64位向32位兼容

栈和堆

栈内存首先是一片内存区域,存储的都是局部变量,凡是定义在方法中的都是局部变量(方法外的是全局变量),for循环内部定义的也是局部变量,是先加载函数才能进行局部变量的定义,所以方法先进栈,然后再定义变量,变量有自己的作用域,一旦离开作用域,变量就会被释放。栈内存的更新速度很快,因为局部变量的生命周期都很短。

存储的是数组和对象(其实数组就是对象),凡是new建立的都是在堆中,堆中存放的都是实体(对象),实体用于封装数据,而且是封装多个(实体的多个属性),如果一个数据消失,这个实体也没有消失,还可以用,所以堆是不会随时释放的。

进程和线程

进程: 一个正在运行的程序,为系统中分配和管理内存资源的最小单元
线程: 程序执行的最小单元(函数)

进程

  • 孤儿进程: 一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程所收养,并由init进程对它们完成状态收集工作。
  • 僵尸进程: 一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
  • 守护进程: 守护进程就是在后台运行,不与任何终端关联的进程,通常情况下守护进程在系统启动时就在运行,它们以root用户或者其他特殊用户(apache和postfix)运行,并能处理一些系统级的任务。

如何处理僵尸进程:

  1. 子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait进行处理僵尸进程。
  2. fork两次,父进程fork一个子进程,然后继续工作,子进程fork一个孙进程后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收 还要自己做。两次fork的原理是将子进程成为孤儿进程,从而其的父进程变为init进程,通过init进程可以处理僵尸进程。

多进程

优点:

  • 资源隔离,不同进程变量之间不会相互冲突
  • 每个进程相互独立,子进程崩溃不影响主进程(安全)
  • 每个进程能使用的空间很大(4G)
  • 可以尽量减少线程加锁/解锁的影响,极大提高性能(IPC很少涉及加锁)

缺点:

  • 多进程调度开销较大(需要上下文切换)
  • 进程间通讯效率低,比较适合小数据量传送(涉及IPC)

多线程

优点:

  • 共享内存和变量,数据交互效率高
  • 程序逻辑和控制方式简单

缺点:

  • 共享内存和变量处理不好,可能会发生冲突
  • 可用空间相互受限,且线程数量过多影响性能提升
  • 一个线程崩了可能影响整个程序
  • 线程之间同步比较麻烦

使用场景

  • 频繁创建和销毁资源优先线程(创建和销毁一个进程代价是很大)
  • 频繁切换,需要大量计算(耗时操作)尽量使用线程
  • 多机分布用进程(跨平台通讯),多核分布用线程
  • 大量数据交互选线程
  • 需要稳定安全时用进程

进程/线程状态和转换

在这里插入图片描述

异常和中断

异常一般指软中断,由程序产生,目的是要产生系统调用,需要切换进程上下文
中断是指硬中断,由硬件产生,目的是响应外设,需要切换中断上下文

中断处理流程:

  1. 中断响应前准备:准备中断向量表
  2. CPU检查是否有中断产生,得到中断号
  3. 查表得到中断程序
  4. cpu根据优先级决定要运行的中断程序
  5. 保存上下文
  6. 跳转到中断程序执行
  7. 执行完,恢复先前状态

上下文

  • 上文: 已执行过的进程指令和数据在相关寄存器与堆栈中的内容(前面执行状态和数据)
  • 正文: 正在执行的指令和数据在寄存器和堆栈中的内容
  • 下文: 待执行的指令和数据在寄存器与堆栈中的内容(即将要执行的程序)

进程上下文

当触发系统调用或异常,进程由用户态切换到内核态时,需要保存当前进程的所有状态(用户态时cpu寄存器中的值,进程状态以及堆栈上的内容),即进程上下文

  • 进程上文: 切换时cpu寄存器中的值,进程状态以及堆栈上的内容
  • 进程下文: 主要指切换到内核态后执行的程序

中断上下文

由硬件产生中断,导致需要切到中断服务程序过程中,需要保存硬件信息和当前状态

  • 中断上文: 看作是硬件传递过来的这些参数和内核需要保存的一些其他环境(主要是当前被中断的进程环境)
  • 中断下文: 主要指马上要执行的中断服务程序

同步和互斥

同步:一个程序/线程的执行依赖于另一个的消息
互斥:共享资源只允许一个进程/线程使用

用户空间与内核通讯

  1. 系统调用,提供特定的用户空间与内核空间的信息传递。
  2. 信号,内核空间出现一些异常时候会发送信号给进程,如SIGSEGV、SIGILL、SIGPIPE等。
  3. /proc,proc可以读取内核空间的信息并且设置部分属性的值,需要循环检测。
  4. 文件,可以通过指定文件的读写操作来实现通信,但是流程不够实时,需要循环检测来实现。
  5. netlink,类似socket通信方式,可以读写大量的数据,实现稍微复杂。
  6. ioctl,可以实现数据量比较少时候的通信。

系统调用

系统调用是操作系统提供给应用程序(程序员)使用的接口,可以理解为一种可供应用程序调用的特殊函数,应用程序发出系统调用请求来获得操作系统的服务。

作用

  • 操作系统作为用户和硬件的接口,向上提供一些简单易用的服务,向下执行具体硬件操作
  • 安全,防止非法操作

分类

设备管理、文件管理、进程控制、进程通信、内存管理

具体如何实现

程序在用户空间中通过0x80中断,将控制权交给内核空间,内核根据调用好调用对应的内核函数,来执行实际处理
如:用户空间read()–> 0x80中断 -->内核空间sys_read()–>scull_fops.read–>scull_read()

linux同步和互斥

原子操作

原子操作内不可被软中断(如系统调用机制)打断,汇编层面实现,操作对象只能是整数

自旋锁

它锁住的是一块临界区,进入临界区时需要先获取自旋锁,在离开临界区时需要释放自旋锁。如果有进程已经获取了自旋锁,但是还没有释放,那么其它想要获取自旋锁的进程就得等(而且不会让出cpu,死等)

读写锁

这种锁允许多个进程同时对同一数据结构进行读操作,但不允许多个进程同时对同一数据结构进行写操作。

信号量

信号量和自旋锁类似,也是为了控制进程进入临界区。本身就是为多核处理器服务的。

但是信号量和自旋锁的最大区别是:

  • 自旋锁禁止cpu抢占,而信号量不禁止cpu抢占。 所以自旋锁在锁住后进程不能进入睡眠,否则将不会有进程抢占cpu而运行。
  • 信号量只能用于进程上下文,而不能用于中断上下文。 由于信号量发生争用的时候,没获取到信号量的进程会睡眠,而中断上下文不允许睡眠(执行过程也不允许抢占),所以中断上下文中只能使用自旋锁;
  • 获取自旋锁的过程,不会主动调用schedule()进行进程切换,而是占着CPU,拼命的自旋,类似于while耗时操作;
  • 信号量中存在一个进程等待队列,为获取锁的进程将挂接到该队列中,然后主动调用schedule()切换进程,让出CPU。适用于长时间持有情况。

内存屏蔽

在指令之间插入一道屏障,两句屏障指令之间的指令不会因为优化而重排。

互斥锁

死锁

添加链接描述

ARM、DSP和FPGA

ARM具有比较强的事务管理功能,可以用来跑界面以及应用程序等,其优势主要体现在控制方面,它的速度和数据处理能力一般,但是外围接口比较丰富,标准化和通用性做的很好,而且在功耗等方面做得也比较好,所以适合用在一些消费电子品方面;

DSP主要是用来计算的,比如进行加密解密、调制解调等,优势是强大的数据处理能力和较高的运行速度。由于其在控制算法等方面很擅长,所以适合用在对控制要求比较高的场合,比如军用导航、电机伺服驱动等方面。

FPGA是可编程逻辑阵列,用硬件描述语言定义各硬件之间连接关系,非常灵活定义不用电路功能,且擅长进行并行处理

IO口工作方式

  • 上拉电阻:将一个不确定的信号,通过一个电阻与电源VCC相连,固定在高电平。在IO口为输入模式且为上拉电阻时,IO口的常态为高电平。

  • 下拉电阻:将一个不确定的信号,通过一个电阻与地GND相连,固定在低电平。在IO口为输入模式且为下拉电阻时,IO口的常态为低电平。

  • 推挽输出:可以输出高、低电平,连接数字器件。推挽结果一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通时令一个三极管截止。(推挽输出的最大特点是可以真正的输出高电平和低电平,且两种电平下都有驱动能力)。IO输出0-接GND, IO输出1 -接VCC

  • 开漏输出:输出端相当于三极管的集电极,要得到高电平状态需要加上拉电阻才行。适合做电流型的驱动,其吸收电流的能力比较强(20mA左右)(开漏输出最主要的特性就是高电平没有驱动能力,需要借助外部上拉电阻才能真正输出高电平)。开漏只能输出低电平,高电平的时候实际上是个高阻态,需要外接电阻来拉高的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值