一、多线程编程的基本概念
1.1 操作系统层面的进程和线程
(1)进程
进程代表了操作系统上运行着的一个应用程序。进程拥有自己的程序块,拥有独占的资源和数据且可以被操作系统调度。
But,即使是同一个应用程序,当被强制启动多次时,也会被安放到不同的进程之中单独运行。
直观地理解进程最好的方式就是通过进程管理器浏览,其中每条记录就代表了一个活动着的进程:
(2)线程
线程附属于进程,一个进程可以包含1个或多个线程且同一进程内的多个线程共享一块内存块和资源。
线程有时候也被称为轻量级进程,是一个可以被调度的单元且维护自己的堆栈和上下文环境。
它的调度受限于该线程所属的进程,也就是说操作系统首先决定执行下一个执行的进程,进而才会调度该进程内的线程。一个线程的基本生命周期如下图所示:
(3)进程和线程的区别
最大的区别在于隔离性,每个进程都会被单独隔离(进程的崩溃不会影响到其他进程,因此进程间的交互也相对困难)
而同一进程内的所有线程则共享内存和资源,并且一个线程可以访问和结束同一进程内的其他线程。
1.2 多线程程序在操作系统中是并行执行的吗?
(1)线程的调度
在计算机系统发展的早期,操作系统层面不存在并行的概念,所有的应用程序都在排队等候一个单线程的队列之中,一个小小的错误将会导致操作系统上的所有程序的阻塞。
在后来的操作系统中,逐渐产生了分时和进程、线程的概念。多个线程由操作系统进行调度控制,决定何时运行哪个线程。
所谓线程调度,是指操作系统决定如何安排线程执行顺序的算法。按常规分类,线程调度可以分为以下两种:
①抢占式调度
抢占式调度是指每个线程都只有极少的运行时间(在Windows NT内核模式下这个时间不会超过20ms),而当时间片用完时该线程就会被强制暂停,保存上下文并把运行权利交给下一个线程。这样调度的结果就是:所有的线程都在被不停地快速切换运行,使得用户感觉所有的线程都在并行运行。
②非抢占式调度
非抢占式调度是指某个线程在运行时不会被操作系统强制暂停,它可以持续地运行直到运行告一段落并主动交出运行权。在这样的调度方式之下,线程的运行就是单队列的,并且可能产生恶意程序长期霸占运行权的情况。
PS:现在很多OS(包括Windows在内)都同时采用抢占和非抢占模式。优先级较高的线程OS采用非抢占式来给予充分的时间运行,而对于普通的线程则采用抢占式模式来快速地切换执行。
(2)线程的并行问题
在单核单CPU的硬件架构上,线程的并行运行完全是用户的主观体验。事实上,在任一时刻只可能存在一个处于运行状态的线程。
在多CPU或多核的架构上,情况则略有不同。多CPU多核的架构则允许系统完全并行地运行两个或多个无其他资源争用的线程,理论上这样的架构可以使运行性能整数倍地提高。