概述
线程是CPU使用的基本单元,由线程ID、程序计数器、寄存器集合和栈组成。它与同一进程的其他线程共享资源,包括代码段、数据段和其他操作系统资源,如打开文件和信号。
在多线程流行之前,为了提高并发性,采用创建新进程的做法。但这样很耗时间和资源。
优点
1、响应度高
多线程增加了对用户的响应程度。有过多线程代码的经历都很容易理解这一点
2、资源共享
默认共享所属进程的内存和资源
3、经济
相对创建进程,经济实惠
4、有效利用多核或多处理器
单线程的进程只能运行在一个CPU上,但多线程可以并行运行在不同的处理器上。
多线程模型
线程分为用户线程和内核线程。用户线程和内核线程之间存在着一种关系。三种常用关系为:
1、多对一
多个用户线程映射到一个内核线程。用户线程管理在用户空间进行,效率会比较高(?这种模式,有点类似node.js,不管多少请求过来,它都是一个单线程进行轮询处理,省去线程切换的开销)。这种模式容易阻塞,并且只能使用一个CPU。
2、一对一
每个用户线程都对应一个内核线程。并发性比多对一好,缺点是开销比较大。并且内核线程数量会有所限制。
3、多对多
三种模式中,并发性最好。多对一,用户线程可以创建很多,但一次只能调度一个线程,形同没有并发性;一对一,并发性好,但线程数量受到限制;多对多,用户线程可以创建任意多,并且相应内核线程可以在多处理器上并发执行,另外衣蛾线程阻塞,可以调用另外一个。
多对多有一个变种:有时也允许将一个用户线程绑定到某个内核线程,其他用户线程仍然对应多个内核线程,称为二级模型。
多对多还有另外一个变种,就是在用户线程和内核线程之间设置一个中间数据结构,称为轻量级进程(LWP)。LWP表现为一种应用程序可以调度用户线程来运行的虚拟处理器。每个LWP与内核线程相连,该内核线程被操作系统调度到物理CPU上执行。也就是说,LWP是用来调度用户线程的?
线程库
分为用户线程库和内核线程库。用户线程只是用户空间的本地函数调用,而内核线程的调用,通常会导致内核的系统调用。
目前三种主要的线程库是:
1、POSIX Pthread
只是接口,而不是实现
2、Win32
3、Java
通常调用宿主操作系统的线程库实现
多线程问题
1、fork() 与 exec()
多线程程序中,线程调用fork()的时候,有的会复制所有线程,有的只复制调用了fork()的线程;如果紧接着调用exec(),那么新进程从头到脚都是新的,包括所有的线程。
2、取消线程
包括
异步取消 :一个线程立即终止目标线程(其他线程?)
和
延迟取消:目标线程不断检查自己是否已被取消
3、信号处理
操作系统通知进程某个事件发生了。信号接收包括
同步接收:谁产生的信号发送给谁
异步接收:发送信号给其他进程。
既然信号发送给进程,那么多线程程序中,哪个线程接收和处理?
1)应用信号的线程
2)所有线程
3)某些固定线程
4)一个特定线程
4、线程池
进程创建之初,就创建一定数量线程,放入池中等待工作。需要工作时,系统唤醒其中一个,将待处理的请求交给它。一旦完成服务,它会返回到池中再等待。
优点:
1)比创建新线程要快
2)限制了线程数量,对不能支持大量并发线程的系统非常重要
5、线程数据
线程共享同一进程内的资源,但有时,线程也会有自己特定的数据。