线程(Thread)
线程有时被称作为轻量级进程(lightweight process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID、当前指令指针(PC)、寄存器集合和堆栈组成。
一个进程由一个到多个线程组成,各个线程之间共享进程的内存够空间(包括代码段、数据段、堆等)以及一些进程级的资源(如打开的文件信号)。
线程调度
在单处理器对应多线程的情况下,并发是一种模拟出的状态。操作系统会让这些多线程轮流执行,每次执行一小段时间(通常是几十到几百毫秒)。每个线程就看“看起来”同时执行。这样的一个不断在处理器上切换到不同线程的行为,称之为线程调度(thread schedule)。在线程调度中,通常至少拥有三种状态,分别是:
运行(running):线程正在运行
就绪(ready):线程可以立即执行,但CPU已经被占用
等待(wait):此时线程正在等待某一事件(通常是I/O发生),无法执行。
处于运行中(running)的线程可以拥有一段可以执行的时间,这段时间称为时间片(Time Slice)。当时间片用尽的时候,该进程进入一个就绪(ready)的状态。如果在时间片用尽之前进程开始等待某事件,那么它进入等待(wait)状态。每当一个线程离开运行状态时,调度系统就会选择一个其他的就绪(ready)状态的线程执行。在一个处于等待(wait)状态的线程所等待的事件发生后,该线程将进入就绪(ready)状态。
线程优先级
线程调度自多任务操作系统问世以来就不断被提出不同的方案和算法。现主流调度算法尽管各不相同,但都带有优先级调度(priority schedule)和轮转法(round robin)的痕迹。
在windows中和linux中,线程的优先级不仅可以由用户手动设置,系统还会根据不同的线程表现自动调整优先级。IO密集型线程(IO bound thread) 一般比CPU密集型线程(CPU bound thread) 更受欢迎,更易得到优先级的提升。
IO bound thread:频繁进入等待状态的线程
CPU bound thread:不频繁等待的线程
优先级调度下,存在一种饿死(starvation)的现象,一个线程被饿死,是指它的优先级较低,始终无法被执行到。为了避免饿死现象,调度系统会逐步提升那些等待了过长时间的得不到执行的线程的优先级。
因此线程优先级改变一般有三种方式:
①用户指定优先级
②系统自动调整优先级(一般根据进入等待状态的频繁程度调整)
③长时间得不到执行而被提升优先级
可抢占线程和不可抢占线程
线程的调度有一个特点,那就是线程在用尽时间片之后会被强制剥夺继续执行的权利,而进入就绪的状态,这个过程叫做抢占(preemption),即之后执行的别的线程抢占了当前线程。
在早期一些系统中(如windows3.1),线程是不可抢占的。线程必须主动发出一个放弃执行的命令,才能让其他线程得到执行。在这样的调度模型下,线程必须主动进入就绪状态,而不是靠时间片来强制进入。当前这种非抢占式线程已十分罕见。
linux的多线程
windows对多线程的实现如果教科书一样标准,windows内核有明确的线程和进程概念。在windows API中,可以使用明确:create process和create thread来创建进程和线程,并且有一系列的API来操作他们。但对linux来说,线程并不是一个普通的概念。
linux对多线程支持颇为贫乏,事实上,在linux内核中并不存在真正意义上的线程概念。linux将所有执行实体(无论是进程还是线程)都称为任务(task),每一个任务概念上都类似于一个单线程的进程,有内存空间、执行实体、文件资源等等。不过,linux下不同任务间可以选择共享内存空间,因而在实际意义上,共享了同一个内存空间的多个任务构建了一个进程,这些任务也就成了这个进程的线程。
使用fork和exec可以创建一个新的任务。(相当于创建进程)
使用clone可以产生一个新的任务,并(可选的)共享当前进程的内存空间和文件等,如此在实际效果上是创建了一个线程。
转载:https://blog.csdn.net/qq_31866157/article/details/113789423