雅趣 2018-04-10
以下内容摘自《程序员的自我修养》
线程(Thread),有时被称为轻量级(Lightweight Process, LWP),是程序执行流程的最小单元。一个标准的线程由线程ID、当前指令指针(PC)、寄存器集合和堆栈组成 。通常意义上,一个进程由一个到多个线程,各个线程之间共享程序的内存空间(包括代码段、数据段、堆等)及一些进程级的资源(如打开文件和信号)。一个经典的线程与进程的关系如图:
大多数软件应用中,线程的数量都不止一个。多个线程可以互不干扰地并发进行,并共享进程的全局变量和堆的数据。那么,多个线程与单线程的进程相比,又有哪些优势呢?通常来说,使用多线程的原因有如下几点:
线程的访问非常自由,它可以访问进程内存里的所有数据,甚至包括其他线程的堆栈(如果它知道其他线程的堆栈地址,那么就是很少见的情况),但实际运用中线程也拥有自己的私有存储空间,包括以下几方面:
不论是在多处理器的计算机上还是单处理器的计算机上,线程总是“并发”执行的。当线程的数量小于等于处理器的数量时(并且操作系统支持多处理器),线程的并发是真正的并发,不同的线程运行在不同的处理器上,彼此之间互不相干。但对于线程数量大于处理器的情况,线程的并发会受到一些阻碍,因此此时至少一个处理器会运行多线程。
在单处理器对应多线程的情况下,并发是一种模拟出来的状态。操作系统会让这些多线程程序轮流执行,每次仅执行一小段时间,(通常是几十到几百毫秒),这样每一个线程就“看起来”在同时执行。这样的一个不断在处理器上切换不同的线程的行为称之为线程调度。在线程调度中,线程通常拥有三种状态,分别是:
线程调度自多任务操作系统问世以来,就不断被提出不同的方案和算法,现在主流的调度方式尽管各不相同,但都带有优先级调度和轮转法。
在windows中可以通过
BOOL WINAPI SetThreadPriority(HANDLE hThread, int nPriority);
来设置线程的优先级,而linux下与线程相关的操作可以通过pthread库来实现;
让我们总结一下,在优先级调度的环境下,线程的优先级改变一般有三种方式。
我们之前讨论的线程调度有一个特点,那就是线程在用尽时间片之后会被强制剥夺继续执行的权利,而进入就绪状态,这个过程叫做抢占。
在不可抢占的线程中,线程主动放弃执行无非是两种情况。
Windows对进程和线程的实现如同教科书一般标准,windows内核有明确的线程和进程的概念,并且有一系列的API来操纵它们。但对于linux来说,线程并不是一个通用的概念。
Linux对多线程的支持颇为贫乏,事实上,在Linux内核中并不存在真正意义上的线程概念。Linux将所有的执行实体(无论是线程还是进程)都称为任务(Task),每一个任务概念上不同任务之间都可以选择共享空间,因此在实际意义上,共享同一个内存空间的多个任务构成了一个进程,这些任务也就成了这个进程中的线程。在Linux下,用以下方法可以创建一个新的任务:
fork函数产生一个和当前进程完全意义的新进程,并和当前进程一样从fork函数里返回。例如如下代码:
pid_t pid; if (pid = fork()) { .... }
fork只能够产生本任务的镜像,因此须要使用exec配合才能启动别的新任务。exec可以用新的可执行映像替换当前的可执行镜像