线程
概述
进程具有两个基本属性使进程成为并发执行的基本单位:
在一些早期的操作系统比如大多数UNIX系统、Linux等,进程同时具有这两个属性。
由于进程是资源的拥有者,在进程创建、撤销、调度切换时,系统需要付出较大时空开销,因而进程的数目不宜过多,切换频率不宜过高,这了并发程度。
然而现实往往出现以下两种情况:
1)一个应用程序可能需要执行多个不同的任务,从而完成一个整体的任务,如word字处理
2)一个应用程序可能需要执行多个相似任务,如网页服务器
解决方案
1)创建多个进程,网页服务器作为单个进程只接收请求,当接收到请求后创建另一个进程以处理请求
2)引入线程,创建多线程的进程,进程中的一个线程监听客户请求,接收到请求时该进程创建一个线程以处理请求
在现代台式电脑上运行的许多软件和软件包都是多线程的。
线程
线程作为CPU调度单位,而进程只作为其他资源分配单位。
线程只拥有必不可少的资源,如线程状态、程序计数器、寄存器上下文和栈,线程同样具有就绪、阻塞和执行三种基本状态,与同属一个进程的其它线程共享进程拥有的全部资源,并可以并发执行。
优点
减小并发执行的时间和空间开销(线程的创建、退出和调度),因此容许在系统中建立更多的线程来提高并发程度。
1)线程的创建时间和终止时间比进程短
2)同一进程内的线程切换时间比进程短
3)同进程内线程间共享内存和文件资源,可直接进行不通过内核的通信
单线程与多线程
进程和线程的比较
并发性:在引入线程的操作系统中,不仅进程间可并发执行,而且一个进程中的多个线程间亦可并发执行,使操作系统具有更好的并发性,能更有效地使用系统资源和提高系统吞吐量
系统开销:在创建或撤消进程时,系统都要为之分配或回收资源,如内存空间、I/O设备等,因此操作系统所付出的开销将明显地大于在创建或撤消线程时的开销
资源:进程间相互,同一进程的各线程间共享资源,而进程内的线程在其他进程不可见
通信:进程间遵循进程间通信,线程间可以直接读写进程数据段来进行通信,线程需要进程同步和互斥手段的辅助以保证数据的一致性
调度:线程上下文切换比进程上下文切换要快很多
内核线程
内核线程依赖于内核,由内核的内部需求在内核空间执行线程创建、调度和管理,它是CPU调度的基本单位。
特点
1)内核维护进程和线程的上下文信息
2)内核完成线程切换
3)一个线程发起系统调用而阻塞,不会影响其他线程的运行
4)时间片分配给线程本身,因而多线程的进程获得更多CPU时间
用户线程
用户线程不依赖于内核,应用进程利用线程库提供的创建、同步、调度和管理线程的函数来控制用户线程,调度在应用软件内部进行,通常采用非抢占式的简单规则,也无需用户态/管态切换,运行速度快。
特点
1)应用进程维护用户线程
2)内核不了解用户线程的存在
3)用户线程切换不需要内核
4)用户线程调度算法可针对具体应用进行优化
5)对于单线程内核,那么一个线程发起系统调用而阻塞会引起整个进程阻塞
6)时间片分配给进程,因而多线程时每个线程速度变慢
内核线程与用户线程的比较
调度方式——内核线程的调度、切换与进程的调度、切换相似,而用户线程则不需内核支持
调度单位——内核线程以线程为单位分配时间片,而用户线程以进程为单位调度,采用时间片轮转调度算法时,以进程为单位分配时间片。
多线程模型
多对一模型
多个用户线程映像一个内核线程,任何时刻只有一个线程可以访问内核,这导致并发性低,若一个用户线程发起系统调用而阻塞,则整个进程阻塞。
一对一模型
一个用户线程映像一个内核线程,这提供良好的并发性,保证了一个用户线程发起系统调用而阻塞时其他线程能够正常运行,但是每创建一个用户线程都需创建一个相应的内核线程,造成了额外开销,所以许多系统会应用中的线程数目。
多对多模型
多对一模型的缺点是不能实现真正的并发,一对一模型的缺点是要应用中的线程数目,
因此更多系统采用多对多模型,这既不应用的线程数,又保证了多个线程可以并发。
系统调用
fork用于创建一个单独、重复的进程,能复制进程中所有线程或仅复制调用fork的线程
exec能够替换整个进程,包括该进程中的所有线程
取消机制
异步取消——一个线程立即终止目标线程,可以在更新与其他线程共享的数据过程中取消,可能无法释放系统范围内的资源
延迟取消——目标线程定期检查是否应该终止,在Pthread中称为取消点
线程池
引入线程池的原因是避免创建和撤销开销,线程的数量。
1)进程创建时就创建一定数量的线程,放入线程池中等待
2)进程收到请求时,唤醒线程池中的一个线程进行处理
3)线程完成工作,返回线程池中继续等待
4)若没有可用的线程,进程会等待,直到有空线程为止
线程池中所有线程只创建和撤销一次,在线程池中复用能减小开销,且用现有线程提供服务比创建线程快,但是使用线程池了线程的数量
影响线程池效率的因素:CPU数量、物理内存量、预期的并发请求数
线程库
线程库为程序员提供创建和管理线程的API,实现线程库有两种方法:
1)在用户空间提供一个没有内核支持的库
2)实现由操作系统直接支持的内核级的库
Pthreads:是线程行为的规范而不是实现,实现取决于库的开发,常见于UNIX操作系统
Windows线程:Windows系统上的内核级库,许多方面类似于Pthreads
Java线程:Java线程是程序执行的基本模型,Java线程由JVM控制,线程通过扩充线程类或实现可运行接口创建
扩充线程类
实现可运行接口
创建线程
Java线程管理
挂起——暂停当前线程的运行
睡眠——让当前线程入睡指定的时间
恢复——再执行被挂起的线程
停止——停止一个线程的执行