校招季——进程与线程的概念

2013/08/15,第四天。昨天总结完了《现代操作系统》的前几章,后面的部分看了一遍,实在不想记笔记了,太杂了。

  第2章  进程与线程

2.1  进程

2.1.1 进程模型

一个进程就是一个正在执行程序的实例,包括程序计数器、寄存器和变量的当前值。理解进程的另一个角度是,用某种方法把相关的资源集中在一起。进程有存放程序正文和数据以及其它资源的地址空间,包括打开的文件、子进程、报警、信号处理程序、账号信息等。

每个进程都认为它独占CPU,这是通过快速切换进程来实现的,这种切换称作多道程序设计。

2.1.2 创建进程

Unix中只有fork一种系统调用来创建进程,它会创建一个与调用进程相同的副本。fork后,父子进程拥有相同的存储映像、同样的环境变量和同样的打开文件。

子进程可以执行exec系统调用,运行一个新的程序。父进程与子进程有不同的地址空间,其中一个进程对地址空间的修改对另一个进程不可见。

2.1.3 终止进程

进程终止的条件:

1.   自愿退出,包括正常退出和出错退出。Unix中用exit系统调用退出进程。

2.   非自愿退出,包括严重错误或被其他进程杀死。进程引起的错误通常会产生信号导致进程终止。Unix中的kill系统调用用来杀死其他进程。

2.1.4 进程的层次结构

Unix中进程和它的所有后裔共同组成一个进程组。Windows中没有进程层次的概念。

2.1.5 进程的状态

进程有四种状态:

1.   运行态:实际占用CPU

2.   就绪态:可运行,但因其他进程正在运行而暂停。

3.   阻塞态:逻辑上不能继续运行,等待外部事件。

4.   终止态:不能切换到前3种状态,等待回收。

运行态和就绪态间的切换是由进程调度程序引起的。

2.1.6 进程的实现

操作系统维护一个结构数组,即进程表,每个进程占用一个表项,表项中包含进程的状态:用于进程管理的状态、用于存储管理的状态、用于文件管理的状态,这些是进程由运行态转换到就绪态或阻塞态时必须保存的信息,用来保证进程随后能再次启动。

2.2  线程

2.2.1 线程的使用

为什么要有线程?

1.   通过将应用程序分解成可以准并行运行的多个顺序线程,程序设计模型会变得更简单。

2.   多个线程可以共享同一个地址空间和所有可用数据,这是多进程模型无法表达的。

3.   线程比进程更轻量级,创建、撤消和切换都更快。

4.   如果同时存在大量的计算和大量的I/O处理,多线程允许这些活动重叠进行,性能更好。

5.   CPU系统中,同时可以有多个线程并行运行,这种系统中多线程能充分利用系统性能。

2.2.2 线程模型

线程中有程序计数器、寄存器、堆栈。进程用于把资源集中到一起,线程则是在CPU上被调度的实体。

同一个进程中并行运行多个线程,是对在同一台计算机上并行运行多个进程的模拟。线程有时也被称为轻量级进程。

所有的线程都有相同的地址空间,还共享打开文件集合、子进程、报警及相关信号。线程可以操纵其他线程的堆栈,线程间是没有保护的,因为:1)不可能;2)没必要,不同的线程都属于同一个用户,彼此间不可能有恶意。

所有线程都是平等的,没有层次关系。但主线程有特殊性:从它的启动函数(main函数)返回会导致进程结束。

2.2.3 Posix线程

所有Pthread都含有一个标识符、一组寄存器和一组存储在结构中的属性,包括堆栈大小、调度参数等。

常用的Pthread函数调用:

1.   pthread_create:创建新线程,返回线程标识符。

2.   pthread_exit:终止线程并释放栈。

3.   pthread_join:等待某线程结束。

4.   pthread_yield:主动释放CPU给其他线程。

5.   pthread_attr_init:建立关联一个线程的属性结构并初始化为默认值。

6.   pthread_attr_destroy:删除一个线程的属性结构,不会影响调用它的线程。

2.2.4 线程的实现

线程包可以在用户空间中或内核中实现。

第一种方式把整个线程包放在用户空间中,内核对线程包一无所知,内核只会参与进程管理。

优点:

1.   用户级线程包可以在不支持线程的操作系统上实现。

2.   用户级线程包需要维护线程表,保存线程状态和调度过程都只是本地过程,整个线程的切换可以在几条指令内完成,要比陷入内核快得多。

3.   允许每个进程有自己定制的调度算法。

缺点:

1.   很难让每个线程阻塞于系统调用时不影响其他线程。

2.   一个线程开始运行后,除非自愿放弃CPU,否则其他线程不能运行。

3.   多线程常用于经常发生线程阻塞的应用中,这种应用会放大上面所说的问题。

如果在内核中实现线程,则由内核维护线程表。所有能够阻塞线程的调用都以系统调用的形式实现。内核的调度单位为线程。

这种实现解决了上面用户级线程包的问题,但在性能上损失很大。

可以将这两种实现混合起来,将线程分为内核线程和用户线程两种,内核只识别并调度内核线程,每个内核线程可以被多个用户线程多路复用。

2.3  进程间通信

进程间通信可以归纳为三个问题:1)信息传递;2)互斥;3)同步。

多个进程读写某些共享数据,最后的结果取决于进程运行的精确时序,称为竞争条件。

一种优先级反转问题:有两个进程,H优先级高,L优先级低,调度规则为H就绪就可以运行。某时刻L处于临界区中,H变到就绪态,此时H开始运行,于是等待L离开临界区,但因为LH抢占,不会被调度,也就不会离开临界区。

2.3.1 忙等待的互斥

几种实现互斥的方案:

1.   屏蔽中断:最简单的方案,但效果不好,因为把屏蔽中断的权力交给用户进程是不明智的。

2.   锁变量:也不好,对锁变量的修改和测试不是原子操作。

3.   忙等待:非常浪费CPU时间,只有在等待时间非常短时才能用此方案。用于忙等待的锁称为自旋锁。

4.   Peterson算法:对忙等待的一种改进。

5.   TSL指令:需要硬件支持,锁住内存总线,以禁止其他CPU在本指令结束前访问内存。可用XCHG替代TSLIntelX86CPU在低层同步中使用XCHG

2.3.2 睡眠与唤醒的互斥

信号量、互斥量、条件变量。

有一种高级同步原语,叫做管程,是由过程、变量及数据结构等组成的一个集合。任一时刻管程中只能有一个活跃过程。管程是编程语言的一部分,进入管程时的互斥由编译器负责。

实现了管程的编程语言很少。

2.3.3 消息传递

可以用消息传递来实现通信和同步。消息传递本身需要互斥。它的设计要点:

1.   消息的丢失和确认。

2.   避免重复的消息。

3.   验证消息来源的身份。

并行程序中经常使用消息传递。

2.3.4 屏障

屏障用于为程序划分阶段,除非所有的线程都就绪准备下一阶段,否则任何线程都不能进入下一阶段。

2.4  调度

进程切换的代价是比较高的:用户态切换到内核态——保存进程状态——保存内存映像——选定调度进程——装入新进程的内存映像——新进程开始运行。除此之外,进程切换还会使整个内存高速缓存失效。

2.4.1 进程行为

1.   计算密集型:绝大多数时间花在CPU运算上。

2.   I/O密集型:绝大多数时间花在等待外部设备而阻塞上。

随着CPU越来越快,更多的进程倾向为I/O密集型。

2.4.2 何时调度

1.   创建新进程后,父子进程都处于就绪态,可以任意决定哪个先运行。

2.   一个进程退出时,从就绪进程中选择一个。

3.   进程阻塞时,必须选择另一个进程运行。

4.   发生I/O中断时,如果有进程阻塞于此设备,该进程就进入就绪态。

非抢占式调度算法:进程会一直运行到阻塞或自动释放CPU,即在时钟中断时不会进行调度。

抢占式调用算法:进程运行时间达到某值时就被挂起,需要在时钟中断时调度。

如果没有可用的时钟,只能采取非抢占式调度算法。

2.4.3 调度算法的目标

1.   所有系统:

a)   公平:给每个进程公平的CPU份额。

b)   策略强制执行:必须保证能强制执行指定的策略。

c)   平衡:保证系统的所有部分都忙碌。

2.   批处理系统:

a)   吞量:每小时最大作业数。

b)   周转时间:从提交到终止间的最小时间。

c)   CPU利用率:保持CPU始终忙碌。

能使吞吐量最大的算法不一定有最小的周转时间。CPU利用率不是一个好的度量参数,真正有价值的是将吞吐量和周转时间结合起来。

3.   交互式系统:

a)   响应时间:快速响应请求。

b)   均衡性:满足用户的期望。

4.   实时系统:

a)   满足截止时间:避免丢失数据。

b)   可预测性:在多媒体系统中避免品质降低。

2.4.4 批处理系统中的调度

1.   先来先服务:非抢占算法。保证了公平性,缺点是性能低

2.   最短作业优先:能保证周转时间最短。但只有在所有作业都可同时运行时才是最优的。

3.   最短剩余时间优先:可以使新的短作业获得良好的服务。

2.4.5 交互式系统中的调度

1.   轮转调度:每个进程分配一个时间片。时间片太短会导致过多的进程切换;太长会导致短的交互请求的响应时间变长。设为20ms~50ms比较合理。

2.   优先级调度:每个进程一个优先级,最高优先级的就绪进程先运行。优先级可以静态赋予或动态赋予。

3.   多级队列:高优先级的进程被调度后优先级降低,同时时间片增长。为计算密集型进程赋予长的时间片会减少切换次数,效率更高。

4.   最短进程优先:需要根据进程过去的行为推测它的执行时间。

5.   保证调度:保证每个进程获得的CPU时间。需要跟踪各进程自创建以来使用的CPU时间。

6.   彩票调度:根据优先级赋予每个进程一定数量的彩票,调度时随机抽取一张彩票,并选择它属于的进程。

7.   公平分享调度:调度不光以进程为单位,还以用户为单位。

2.4.6 实时系统中的调度

实时系统可以分为硬实时和软实时。实时系统中的事件可以分为周期性事件和非周期性事件。能在一个周期内处理完所有事件的实时系统称为是可调度的。

实时系统的调度算法可以是静态或动态的,前者在系统开始运行前作出调度决策,后者在运行时进行决策。

2.4.7 线程调度

用户线程和内核线程的差别在于性能。

从进程A的一个线程切换到进程B的一个线程,其代价高于运行进程A的第2个线程。

2.5  经典的IPC问题

2.5.1 哲学家就餐问题

5个哲学家围成一圈,每个人面前有一碗饭,左右各有一支筷子,因此共有5支筷子。哲学家的生活中只有思考和吃饭两个阶段。当他觉得饿了,需要同时获取到左边和右边的筷子才能吃饭。当他思考时就会放下两支筷子。寻找一种不会产生死锁的方法。

1.   所有人都先拿左边的筷子再拿右边的筷子,会死锁。

2.   拿到左边的筷子后查看右边的筷子,若不可用则回退,过段时间再重来。会死锁。

3.   回退后的等待时间随机化,正常应用中不会产生问题,高可靠性的应用中不行。

4.   每个哲学家一个状态,一个信号量,吃饭时标记自己为饿了,查看左边和右边的筷子,若不可用则阻塞于自己的信号量上;思考时标记自己在思考,检查左边和右边的哲学家,若他们的两个筷子都可用则发信号给他们的信号量。不会产生死锁,且能获得最大的并行度。

2.5.2 读者-写者问题

在一个读者到达,且一个写者在等待时,读者在写者之后被挂起,而不是立即允许进入,能避免死锁。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值