LinuxC++面向对象多线程学习笔记_多任务与多线程编程

多任务(multitask)同时执行多个进程,而多线程(multithread)允许单个进程同时执行多个线程。

  1. 多任务编程

当OS使用一个规划策略允许两个或更多进程并发共享一个CPU时,它称做多任务编程(multitasking)或多程序编程(multiprogramming)。

多任务可以在3个级别上发生:

a. 对话级; b. 进程级; c. 线程级。

对话级的多任务由用户控制。用户运行若干应用程序或对话时发生用户控制多任务(user-controlled multitask)。对话创建一个虚拟计算机以及它的键盘、鼠标和屏幕,当执行一个对话时,用户可以决定切换到另一个对方中。因为由用户决定哪一个应用或对话位于前台或后台,以及终止哪一个应用或对话,所以称之为用户控制多任务。用户也可以打开新应用程序或对话。

在对话间,多个进程可以并发激活,通过相互合作来完成一个目标。当在一个对话中有多个进程激活时,这称做进程级多任务编程(process-level multitasking)。

进程由多个单独的任务组成,每个任务都有自己的控制流程,这些任务充当轻量级的进程即线程。进程内的多线程并发执行称做多线程编程(multithreading)。

对话间的多任务是一个高级别的多任务,它受用户所控制。进程间的多任务以及多线程在低级别上实现,并受到程序员的严重影响。程序员创建进程,并决定每个进程的线程数,还决定任务的优先权以及什么时候挂起,什么时候终止。

多任务的目的是增加系统完成的工作量。多任务通过保持资源(CPU,I/O等)的繁忙而且试图防止它们在系统中处于非激活状态来使用资源。大部分任务不能不间断执行,因为它们需要等待I/O或另一个任务的终止,此时就可让给其它任务来使用资源,以充分提高CPU的使用率。

  1. 合作和抢占式多任务

多任务使用两种规划原则来实现:合作(cooperation)与抢占(preemption)。通过抢占,OS保持对处理器的控制。一旦任务提交给处理器后,它只执行短暂的时间段,然后分配另一个任务给处理器。而通过合作,任务分配给处理器后,它就不能被抢占。为了让另一个任务执行,运行任务必须自愿从处理器中删除自身。

2.1 合作多任务

合作多任务允许任务控制处理器,OS放弃对处理器的控制,任务一旦拥有处理器就可以选择运行任意长的时间而不会被系统操作抢占,除非它自己放弃了控制权。在这样的OS下,任何任务都可能发生饥饿。合作多任务使用优先权规划。如果阻塞或挂起一个高优先权的任务,则低优先权任务被分配给处理器,它可以独占处理器,不允许高优先权任务有执行时间。

拥有处理器的任务可以在等待一个I/O请求完成时一直占据处理器。系统依赖于任务间的合作来保持系统平稳运行。任务必须与所有的普通系统函数合作,否则这些函数就会受到侵犯,因为任务正占据着处理器。

通过合作实现多任务的方式如下:

a. 设置它使用处理器的时间限制;

b. 在代码中设置逻辑断点,在此处放弃处理器;

c. 当发出I/O请求时放弃处理器;

d. 当系统操作需要立即执行时放弃处理器;

e. 放弃处理器允许交互任务使用处理器;

f. 放弃处理器允许系统对中断作出反应。

合作多任务的优点如下:

a. 对时间重要任务和通信任务不会被抢占;

b. 程序员控制了系统的操作;

c. 强迫程序员按防错方式设计任务,有目的性地允许合作;

d. 任务的执行和反应更具可预测性;

e. 一种公平的规划方法:引入的高优先权任务不能取代已经运行的任务;

f. 比抢占式规划开销低,抢占式规划因为频繁的上下文切换,所以需要在主存储器中保持多个任务。

合作多任务的缺点:

a. 允许任务独占处理器;

b. 多任务只在任务得到处理器时才发生。由程序员决定是否发生多任务;

c. 可能得不到可接受的反应时间;

d. 程序员控制了系统的操作;

e. 程序员在设计任务时,必须考虑OS的操作,而不是排它性地设计任务的功能性;(无疑这样对程序员的要求高了不少)

f. 没有设计为合作的任务可以阻止正常合作任务的执行;

g. 长时间运行任务将使短时间运行任务等待;

h. 设计不良的任务可能导致整个系统停顿。

2.2 抢占式多任务

抢占式多任务是多任务的一种形式,在这种形式中,OS不会等到任务自愿将处理器交还系统,让它分配另一个任务给处理器。每个任务运行短暂的一段时间,称为时间片断(slice)或时间片(quantum),当时间片过期时,OS抢占执行并分配另一个任务给处理器。任务在时间段过期前,可以自愿放弃处理器;但如果仍然执行,则该任务会被删除。

抢占式多任务的优点:

a. 不允许任何任务独占处理器;

b. 设计不良的任务不限止其它任务的执行,而且不导致整个系统的停顿,因为它们将被抢占;

c. OS保持对系统的控制;

d. 设计任务时,程序员不必考虑系统的操作,而可以排它性地设计任务的功能性;

e. 通过分配每个任务一段处理器时间来推进任务的执行;

f. 由于上下文的切换,所以有可接受的反应时间;

g. 新引入的高优先权可以抢占运行任务;

h. 多任务由OS执行,而不是由程序员来执行。

抢占式多任务的缺点:

a. 时间敏感任务和通信可能被抢占;

b. 比合作式多任务开销大,因为频繁的上下文切换,所以必须在主存储器中保持多个任务。

2.3 时间片的大小

如果时间片太长,一旦某个任务得到处理器,它就执行到完成,而不是多任务地执行,系统操作性能就会降级到连续性执行;而如果时间片过短,开销变得更为重要。时间片的长度随系统的不同而不同,在不同的条件下也可能发生变化,还可能针对不同类型的任务而有所不同。

一些OS允许更改时间片的长度。时间片有一个最小值和一个最大值,以毫秒为单位。用户按这种方式定义后,它就成为一个静态值。缺省时间片为动态,根据系统装载的不同,时间片的大小也会改变。对于允许这种变化的系统,在文件config.sys中定义时间片的大小。

  1. 多处理器下的多线程

非对称和对称系统都处于一种紧密耦合(tightly coupled)环境中。紧密耦合环境意味着,处理器处于一种使用单一操作系统控制所有处理器的单一系统中。这些处理器有一个用于通信的共享内存区域,只要在这里存在共享的内容,就有可能存在对它的竞争。通过在处理器间分布任务装载、使用阻塞或每个处理器的缓冲内存,可以将这种竞争降到最低限度。

紧密耦合环境与松散耦合环境相反。在松散耦合环境中,存在两个或更多的独立系统,它们各自有自己的存储器和操作系统。这种系统通过消息传递或远程过程建立通信链接,相互间可以访问对方的文件。在紧密耦合环境中,处理器访问相同的就绪队列。在松散环境中,独立系统保持有自己的单独就绪队列。单个进程的线程可以利用紧密耦合的多处理器。

3.1 非对称多处理器处理

在非对称组织的多处理器处理系统中,一个处理器执行一个设计好的任务。设计用一个处理器(譬如处理器0)一执行输入和输出,其它处理器(譬如处理器1到处理器n)执行计算密集型的任务。只要需要执行I/O,就用处理器0来执行,它只执行操作系统,而用户任务不能在执行OS所在的处理器上执行。非对称多处理器处理用于非对称硬件上,例如一个处理器和一个协理器(coprocessor)。

非对称多处理器给其上的每个处理器进行了职能划分,限定了其分别所可执行任务的种类,因此它允许处理器处理空闲(即使有任务在等待执行),所以整体上减少了处理器的吞吐量。

3.2 对称多处理器处理

多处理器对称组织具备一个相互等同的处理器池(pool of processor)。处理器不是设计用于执行特殊类型的任务。任何处理器都可以执行系统或用户线程,都可以控制某个I/O设备或引用内存地址。操作系统线程可在任何处理器上执行,而且从一个处理器漂移到另一个处理器上,所以操作系统代码需要重新进入。某些系统有一个设计作为执行处理器的处理器,它负责系统数据和系统函数。对称多处理器处理是一种更稳固、可靠的环境,如一个崩溃,它就不再属于可用处理器之列了。

3.3 具有多处理器的多线程处理模型

创建具有同时执行多线程的进程强迫程序员按并行的方式来思考,程序员必须考虑在同一时刻所有执行的形为,以及它们之间相互影响的方式,或者一些全局结构。同时执行的任务可以相互独立发挥作用,或者在某个点,可能需要其它任务的同步或合作。需求同步化时,该任务可能不能继续执行,直到其中一个任务完成为止。需求合作可能意味着该任务从其它将完成工作的任务中获取一些数据。完成与其它任务独立发挥作用的同时(simultaneous)任务则不需要同步(synchronization)。事实上,它们可以不按特定的顺序来执行。

容易将完全独立的线程分配给它们自己的处理器来执行。其它任务可能需要一定程度的同步和合作。需要用一个范例为并发任务建立模型。模型将特征化如何将工作分解成线程,以及线程如何同步化。模型应当包含数据结构中的任何共享数据,使用某种类型的阻塞机制可以保护这些数据结构,使访问同步化而避免数据竞争。

在多处理器处理环境中,一个用于多线程进程的模型例子是主-次线程模型(primary-secondary thread model)。在这个模型中,一个线程(指主线程)将任务分解,并分布到次线程中。这些次线程在同一时间调用。主线程一直等到所有的次线程都完成了它们的任务,然后才继续。主线程与次线程同步执行。主线程根据事先知道的工作调用线程,将工作大体平分为相等的部分。

管道线模型:工作分为几个执行阶段。这些阶段创建一个管道线或装配线,在每个阶段执行指定的任务部分。管道线中的每个阶段执行不同或相同任务。这些阶段并行执行。在管道线中为每个阶段分配一个线程。

工作堆:分配任务以队列形式存在于工作堆中的多个块。工作线程从堆中请求任务来执行。可以给工作堆添加工作线程。请求可以得到保证,直到工作堆为空。工作堆不同于主-次线程模型,主-次模型需要预先知道将要完成的工作量,然后创建相应数量的次线程。而在工作堆模型中,预告不知道工作量,工作线程可能导致执行额外的任务。

  1. 规划策略

规划策略决定什么时候分配处理器,以及分配哪一个线程给处理器。OS可能使用优先权规划,其中最高优先权线程被分配给处理器。当存在多个同一优先类(或)优先级的线程时,使用另一个规划方案。

规划的发生级别有:

a. 线程规划;

b. 进程规划;

c. 中间级规划。

像进程、线程这样的低级别规划由分派器来执行(分派器常驻在主存储器中)。中间级别规划决定允许哪一个进程竞争处理器。竞争处理器的进程保存在就绪队列中。在这一级别,进程可以挂起,由于系统负载的变化也可能恢复。这个级别的规划是进入系统的进程与竞争处理器进程之间的一个缓冲器。

规划策略的目的是决定哪一个进程或线程使用处理器以及应当何时使用处理器。它应当偏向于占有重要资源的任务。低优先权任务可能锁定资源,而这些资源将被其它具有较高优先权任务所使用或被系统中的许多激活任务所使用,因此可能会导致死锁。这种规划机制应当偏向于锁定这类资源的进程或线程,使得它可以释放资源。

规划策略目标:

a. 最大化吞吐量;

b. 强制优先权;

c. 根据实际,尽量公平;

d. 最小化开销;

e. 避免无限延迟和饥饿;

f. 偏向于占据了其它任务所需资源的任务;

g. 在需要时,有充足的可用资源,让反应时间可接受;

h. 不应当在重系统负荷下崩溃。

常用的规划策略如以下:

FIFO(非抢占式);SJF(最短任务优先,同样非抢占式);RR(轮询,抢占式的);STR(最短剩余时间,也是抢占式的),HRN(最高反应率其次,非抢占式的)。
更多面试资料与学习视频与笔记微信搜索关注零声学院公众号领取!在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/lingshengxueyuan/article/details/107542086