进程与线程
进程与线程
对于有线程系统:
- 进程是资源分配的最小独立单位
- 线程是资源调度的最小独立地位
对于无线程系统:
- 进程是资源调度、分配的独立单位
进程之间的通信的方式
- 管道
- 有名管道:一种半双工的通信方式,允许无亲缘关系的线程通信
- 无名管道:一种半双工的通信方式,只能在具有亲缘关系的进程中使用。
- 共享内存:映射一段能被其他进程访问的内存,这段共享内存由一个进程创建,但是可以被其他进程所访问。
- 信号量:一个计数器,控制多个进程对共享资源的访问。
- 信号:一种通信方式,通知接受通知的进程某件事情已经发生。
- 消息队列:消息的链表,存放在系统内核中,并由消息队列标识符标识。
- 套接字:可用于不同进程或者进程间的通信。
线程之间的通信的方式
- 锁机制
- 互斥锁:提供了以排它方式阻止数据结构被并发修改的方法。
- 读写锁:允许多个线程同时读共享数据,而对写操作互斥。
- 条件变量:可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。
- 信号量机制:包括无名线程信号量与有名线程信号量
- 类似于进程间的信号处理
线程间通信的主要目的是用于线程同步,所以线程没有象进程通信中用于数据交换的通信机制。
进程的中断
一、概念
中断是指在CPU正常运行期间,由于内外部事件或由程序预先安排的事件引起的CPU暂时停止正在运行的程序,转而为该内部或外部事件或预先安排的事件服务的程序中去,服务完毕后再返回去继续运行被暂时中断的程序。Linux中通常分为外部中断(又叫硬件中断)和内部中断(又叫异常)。
在实地址模式中,CPU把内存中从0开始的1KB空间作为一个中断向量表。表中的每一项占4个字节。但是在保护模式中,有这4个字节的表项构成的中断向量表不满足实际需求,于是根据反映模式切换的信息和偏移量的足够使得中断向量表的表项由8个字节组成,而中断向量表也叫做了中断描述符表(IDT)。在CPU中增加了一个用来描述中断描述符表寄存器(IDTR),用来保存中断描述符表的起始地址。
二、Linux的中断处理
2.1 系统中断号
由上述中断定义可知,系统中断向量表中共可保存256个中断向量入口,即IDT中包含的256个中断描述符
中断向量号 异常事件 Linux的处理程序
0 除法错误 Divide_error
1 调试异常 Debug
2 NMI中断 Nmi
3 单字节int 3 Int3
4 溢出 Overflow
...
2.2 中断请求
-
中断请求概述
外部设备当需要操作系统做相关的事情的时候,会产生相应的中断。
设备通过相应的中断线向中断控制器发送高电平以产生中断信号,而操作系统则会从中断控制器的状态位取得那根中断线上产生的中断。而且只有在设备在对某一条中断线拥有控制权,才可以向这条中断线上发送信号。也由于现在的外设越来越多,中断线又是很宝贵的资源不可能被一一对应。因此在使用中断线前,就得对相应的中断线进行申请。无论采用共享中断方式还是独占一个中断,申请过程都是先将所有的中断线进行扫描,得出哪些没有被占用,从其中选择一个作为该设备的IRQ。其次,通过中断申请函数申请相应的IRQ。最后,根据申请结果查看中断是否能够被执行。 -
中断请求的实现
中断的分类
中断处理切为两半。中断处理程序是上半部——接受中断,他就立即开始执行,但只有做严格时限的工作。能够被允许稍后完成的工作会推迟到下半部去,此后,在合适的时机,下半部会被终端执行。上半部简单快速,执行时禁止一些或者全部中断。
下半部稍后执行,而且执行期间可以响应所有的中断。这种设计可以使系统处于中断屏蔽状态的时间尽可能的短,以此来提高系统的响应能力。
上下半部划分原则
- 如果一个任务对时间非常敏感,将其放在中断处理程序中执行;
- 如果一个任务和硬件有关,将其放在中断处理程序中执行;
- 如果一个任务要保证不被其他中断打断,将其放在中断处理程序中执行;
- 其他所有任务,考虑放置在下半部执行。
什么是下半部
中断是一个很霸道的东西,处理器一旦接收到中断,就会打断正在执行的代码,调用中断处理函数。如果在中断处理函数中没有禁止中断,该中断处理函数执行过程中仍有可能被其他中断打断。出于这样的原因,大家都希望中断处理函数执行得越快越好。
另外,中断上下文中不能阻塞,这也限制了中断上下文中能干的事。
基于上面的原因,内核将整个的中断处理流程分为了上半部和下半部。上半部就是之前所说的中断处理函数,它能最快的响应中断,并且做一些必须在中断响应之后马上要做的事情。而一些需要在中断处理函数后继续执行的操作,内核建议把它放在下半部执行。
拿网卡来举例,在linux内核中,当网卡一旦接受到数据,网卡会通过中断告诉内核处理数据,内核会在网卡中断处理函数(上半部)执行一些网卡硬件的必要设置,因为这是在中断响应后急切要干的事情。接着,内核调用对应的下半部函数来处理网卡接收到的数据,因为数据处理没必要在中断处理函数里面马上执行,可以将中断让出来做更紧迫的事情。
下半部实现机制之软中断
软中断作为下半部机制的代表,是随着SMP(share memory processor)的出现应运而生的,它也是tasklet实现的基础(tasklet实际上只是在软中断的基础上添加了一定的机制)。软中断一般是“可延迟函数”的总称,有时候也包括了tasklet(请读者在遇到的时候根据上下文推断是否包含tasklet)。它的出现就是因为要满足上面所提出的上半部和下半部的区别,使得对时间不敏感的任务延后执行,软中断执行中断处理程序留给它去完成的剩余任务,而且可以在多个CPU上并行执行,使得总的系统效率可以更高。它的特性包括:
- 产生后并不是马上可以执行,必须要等待内核的调度才能执行。软中断不能被自己打断,只能被硬件中断打断(上半部)。
- 可以并发运行在多个CPU上(即使同一类型的也可以)。所以软中断必须设计为可重入的函数(允许多个CPU同时操作),因此也需要使用自旋锁来保护其数据结构。
进程饥饿
一、概念
在一个动态系统中,资源请求与释放是经常性发生的进程行为.对于每类系统资源,操作系统需要确定一个分配策略,当多个进程同时申请某类资源时,由分配策略确定资源分配给进程的次序。 资源分配策略可能是公平的(fair),能保证请求者在有限的时间内获得所需资源;资源分配策略也可能是不公平的(unfair),即不能保证等待时间上界的存在。 在后一种情况下,即使系统没有发生死锁,某些进程也可能会长时间等待.当等待时间给进程推进和响应带来明显影响时,称发生了进程饥饿(starvation),当饥饿到一定程度的进程所赋予的任务即使完成也不再具有实际意义时称该进程被饿死(starve to death)。
二、例子
考虑一台打印机分配的例子,当有多个进程需要打印文件时,系统按照短文件优先的策略排序,该策略具有平均等待时间短的优点,似乎非常合理,但当短文件打印任务源源不断时,长文件的打印任务将被无限期地推迟,导致饥饿以至饿死。
当等待时间给进程的推进和相应带来明显的影响时,就称发生了进程饥饿。当饥饿到一定程度的进程所赋予的任务即使完成也不再具有实际意义时,称该进程被饿死。
当一组进程到达时,CPU根据算法进行进程调度。有的进程因此而需要等待,而不能及时得到资源,这就叫饥饿。进程得到资源时,再完成已经不再具有意义,这就叫做饿死。
参考地址
https://www.cnblogs.com/edver/p/7260696.html
https://www.cnblogs.com/sky-heaven/p/5746730.html
https://blog.csdn.net/robertsong2004/article/details/40376213
https://blog.csdn.net/yang_teng_/article/details/53325280
https://blog.csdn.net/zhangskd/article/details/21992933
https://www.cnblogs.com/widic/p/7392485.html