在进程模型中,计算机上所有可运行的软件,通常也包括操作系统,被组织成若干顺序进程(sequential process),简称进程。一个进程就是一个正在执行程序的实例,包括程序计数器、寄存器和变量的当前值。进程是某种类型的一个活动,它有程序、输入、输出以及状态。
4种主要的事件会导致进程的创建
进程终止的条件
某些系统中,当进程创建了另一个进程后,父进程和子进程就以某种形式继续保持关联。
为了实现进程模型,操作系统维护一张表格(一个结构数组),即进程表(process table)。每个进程占用一个表项。
为什么需要线程?
进程模型基于两种独立的概念:资源分组处理与执行。
线程之间是没有保护的,原因是:
优点
缺点
进程表
每个进程需要有其专用的线程表(thread table)
缺点
进程间通信的是三个问题
两个或多个进程读写某些共享数据,而最后的结果取决于进程运行的精确时序。称为竞争条件。
避免竞争条件解决方案的4个条件
屏蔽中断仅对执行disable指令的那个CPU有效,其他CPU仍将继续运行,并可以访问内存
非原子性操作,与假脱机目录一样的疏漏 。假设一个进程读出锁变量的值并发现它为0,而恰好在它将值设置为1之前,另一个进程被调度运行,将该变量设置为1。当第一个进程再次运行是,它同样也将该值设置为1,则此时同时有两个进程进入临界区中。
严格轮换法主要是因为对同一变量比较了不同的值,防止了比较相同值时,在相同时间点的漏洞
连续测试一个变量直到某个值出现为止,称为忙等待。
用于忙等待的锁称为自旋锁。
临界区外的进程可阻塞其他进程。
perterson解法与严格轮换法的区别在于多了一个数组来记录进程的状态,比较的是对方的状态,所以不会像严格轮换法导致进程外的进程阻塞其他进程。
硬件支持的一种方案
TSL RX,LOCK 测试并加锁,它将一个内存字lock读到寄存器RX中,然后在该内存地址上存一个非零值。
锁住存储总线不同于屏蔽中断。
每个进程有自己的一组寄存器,若线程是在内核中实现的,那么每个线程也有自己的一组寄存器。在TSL测试时锁的值时存在自己的寄存器里面,所以不会有竞争条件发生。
忙等待缺点:
sleep wakeup
if(count ==0) sleep();不是一个原子操作。所以存在,wakeUp 信号丢失问题
唤醒等待位: 当一个wakeup信号发送给一个清醒的进程信号时,将该位置1.随后,当该进程要睡眠时,如果唤醒等待位为1,则将该位清除,而该进程仍然保存清醒。
wakeup唤醒特定的进程。
一个信号量可以为0(表示没有保存下来的唤醒操作)或者值为正值(表示有一个或多个唤醒操作)。
共两个或多个进程使用的信号量,其初值为1,保证同时只有一个进程可以进入临界区,称作二元信号量。
down操作:检查值是否大于0,大于0,将其值减1,并继续;若值为0,则进程将睡眠,此时down操作并未结束。
up操作:对信号量的值增加1。
信号量mutex用于互斥,保存任一时刻只有一个进程读写缓冲区和相关变量。
empty 和 full 用来记录,个信号的数量,避免了,信号的丢失。信号量full和empty用来保证某种事件的顺序发生或不发生。
如果不需要信号量的计数能力,有时可以使用信号量的一个简化版本,称为互斥量。
没有计数能力,解锁和加锁两种状态。
0表示解锁,信号量当是0的时候阻塞。
mutex_lock mutex_unlock
如果有可用的TSL 和 XCHG指令,就可以很容易的在用户空间中实现。
公共缓冲区的两种方案
1.共享数据结构,放在内核中,并且只能通过系统调用来访问。
2.让进程和其他进程共享部分地址空间。
实现了基本的锁(很像互斥锁),但避免了陷入内核,除非它真的不得不这样做。
futex包含两个部分:一个内核服务和一个用户库。
是Linux对轻量级锁和重量级锁的自动转换功能。
互斥量
pthread_mutex_
一种高级同步原语。一个管程是一个由过程、变量及数据结构等组成的一个集合,它们组成一个特殊的模块或软件包。
管程有一个很重要的特性,即任一时刻管程中只能有一个活跃进程,这一特性使管程能有效地完成互斥。
消息传递(message passing)。这种进程间通信的方法使用两条原语send和receive,它们像信号量而不像管程,是系统调用而不是语言成分。
**消息确认:为了防止消息丢失,发送方和接受方可以达成如下一致:一旦接收到信息,接收方马上回送一条特殊的确认(acknowledge)**消息。发送方在一段时间间隔内未收到确认,则重发消息。
收到两次相同消息,用连续的序号来解决此问题。
身份认证(authentication) 问题
在同一台机器上将消息从一个进程复制到另一个进程通常比信号量操作和进入管程要慢。
屏障是准备用于进程组而不是用于双进程的生产者-消费者这类情形的。
在有些应用中划分了若干阶段,并且规定,除非所有的进程都就绪准备着手下一个阶段,否则任何进程都不能进入下一个阶段。
读-复制-更新(Read-Copy-Update,RCU),将更新过程中的移除和再分配过程分离开来。