340 likes | 465 Views
2.4 线程及其实现. 2.4.1 引入多线程的动机 2.4.2 多线程环境中的进程和线程 2.4.3 线程的实现. 2.4.1 引入多线程的动机. 单线程 ( 结构 ) 进程( Single Threaded Process ) 多线程(结构)进程( Multiple Threaded process ). 单线程结构进程给并发程序设计效率带来问题. • 进程切换开销大 • 进程通信代价大 • 进程间的并发性粒度较粗,并发度不高 • 不适应并行计算和分布并行计算的要求 • 不适合客户 / 服务器计算的要求。. 线程的概念 (1).
E N D
2.4 线程及其实现 2.4.1 引入多线程的动机 2.4.2 多线程环境中的进程和线程 2.4.3 线程的实现
2.4.1 引入多线程的动机 • 单线程(结构)进程(Single Threaded Process) • 多线程(结构)进程(Multiple Threaded process)
单线程结构进程给并发程序设计效率带来问题 •进程切换开销大 •进程通信代价大 •进程间的并发性粒度较粗,并发度不高 •不适应并行计算和分布并行计算的要求 •不适合客户/服务器计算的要求。
线程的概念(1) • 操作系统中引入进程的目的是为了使多个程序并发执行,以改善资源使用率和提高系统效率, • 操作系统中再引入线程,则是为了减少程序并发执行时所付出的时空开销,使得并发粒度更细、并发性更好。
线程的概念(2) 解决问题的基本思路: •把进程的两项功能--“独立分配资源”与“被调度分派执行”分离开来, •进程作为系统资源分配和保护的独立单位,不需要频繁地切换; •线程作为系统调度和分派的基本单位,能轻装运行,会被频繁地调度和切换,在这种指导思想下,产生了线程的概念。
进程 进程PCB 资源 线程 控制块 用户栈 核心栈 线程 控制块 用户栈 核心栈 … 线程 控制块 … 线程n 控制块 用户栈 核心栈 存储区 线程 控制块 用户栈 核心栈 存储空间 全局数据 程序代码 线程1 线程1 线程2 线程i 线程1 线程n 2.4.2 多线程环境中的进程与线程 多线程结构进程
多线程环境中进程的定义 进程是操作系统中除处理器外进行的资源分配和保护的基本单位,它有一个独立的虚拟地址空间,用来容纳进程映像(如与进程关联的程序与数据),并以进程为单位对各种资源实施保护,如受保护地访问处理器、文件、外部设备及其他进程(进程间通信)。
多线程环境中的线程概念 线程是操作系统进程中能够独立执行的实体(控制流),是处理器调度和分派的基本单位。线程是进程的组成部分,每个进程内允许包含多个并发执行的实体(控制流),这就是多线程。
线程组成 • 线程惟一标识符及线程状态信息; • 未运行时保存的线程上下文;可把线程看成是进程中一个独立的程序计数器在操作; • 核心栈,核心态下工作时,保存参数,函数调用时的返回地址等; • 用于存放线程局部变量及用户栈的私有存储区。
线程又称轻量进程 •线程运行在进程的上下文中,并使用进程的资源和环境。 •系统调度的基本单位是线程而不是进程,每当创建一个进程时,至少要同时为该进程创建一个线程,否则该进程无法被调度执行。 •Linux线程做法不一样。
线程的状态 • 线程状态有:运行、就绪和阻塞,线程的状态转换也类似于进程。 • 挂起状态对线程是没有意义的,如果进程挂起后被对换出主存,则它的所有线程因共享了进程的地址空间,也必须全部对换出去。
线程管理和线程库(1) • 多线程技术利用线程包(库)提供线程原语集来支持多线程运行, • 有的操作系统直接支持多线程,而有的操作系统不支持多线程。 • 线程包(库)可分成两种:用户空间中运行的线程包(库)和内核中运行的线程包(库)。
线程管理和线程库(2) 线程包(库)提供一组API,支持应用程序创建、调度、撤销和管理线程的运行。基本线程控制原语: •孵化(Spawn):又称创建线程。 •封锁(Block):又称阻塞线程。 •活化(Unblock):又称恢复线程。 •结束(Finish):又称撤销线程。
并发多线程程序设计的优点 •快速线程切换。 •减少(系统)管理开销。 •(线程)通信易于实现。 •(线程)通信易于实现。 •并行程度提高。 •节省主存空间。
多线程技术的应用 进程中线程多种组织方式: 第一种是调度员/工作者模式 第二种是组模式 第三种是流水线模式 多线程技术的应用 •前台和后台工作 •C/S应用模式 •异步处理 •加快执行速度。 •设计用户接口。
2.4.3 线程的实现 从实现角度看,线程分成: •用户级线程ULT(如Java ,Informix) •内核级线程KLT(如OS/2)。 •混合式线程(如,Solaris)。
2.5 Linux进程与线程 • 进程描述符task_struct中包含:进程标识、链接信息、调度信息、文件信息、虚存空间信息、信号处理信息等。 • Linux中认为线程就是共享地址空间及其他资源的进程,故并没有单独为线程定义数据结构,有一套在用户模式下运行的线程库-pthread,但每个线程都拥有惟一隶属于自己的task_struct。
核心栈 esp存放堆栈栈顶指针 8KB • struct task_struct 内核虚存 用户代码 不可见 0xc0000000 用户栈(运行时创建) esp 共享库主存映象区 0x40000000 brk 运行时堆空间 堆(malloc创建) 读/写段 从可执行文件加载 只读段 0x08048000 未 用 0 Linux2.4进程的核心栈、PCB和虚存映象
进程核心栈 进程核心栈 栈顶 栈指针esp current task_struct thread_info{*task … } } 进程的核心栈、*task和task_struct结构 Linux2.6进程的核心栈
Linux进程的运行环境信息thread_info结构 包含: • 进程描述符task_struct指针、 • 当前CPU号、 • 底层标志、 • 线程同步标志、 • 内核抢占计数器等。
Linux2.6 task_struct 增加用于调度的新成员,主要有: • 动态优先级prio • 静态优先级static_prio • 正常优先级normal_prio • 优先级数组prio_array • 进程平均等待时间sleep_avg • 负载平衡权重load_weight等
Linux进程状态 • TASK_RUNNING • TASK_INTERRUPTIBLE • TASK_UNINTERRUPTIBLE • TASK_ZOMBIE。 • TASK_STOPPED • TASK_SWAPPING
创建do_fork( ) 收到SIG_KILL或SIG_CONT 后,执行wake_up( ) TASK_RUNNING wake_up_interruptible() wake_up( ) wake_up() TASK_UNINTERRUPTIBLE TASK_INTERRUPTIBLE 时间 片到 schedule( ) schedulle( ) sleep_on( ) schedule( ) interruptible_sleep_on( ) 占有CPU运行 schedule( ) syscall_trace( ) sys_exit( ) do_exit( ) TASK_STOPPED TASK_ZOMBIE Linux进程状态及转换
2.6Windows 2003进程与线程 • 进程是资源的容器,容纳各种分配到的资源如主存、已打开文件等; • 线程是可被内核调度的执行实体,可被中断,使CPU能转向另一线程执行。 • 进程和线程用对象来实现。
Windows 对象分类(1) Windows 是一个基于对象的操作系统,用对象来表示所有的系统资源。 (1)执行体对象 由执行体的组件实现的对象,用来实现各种外部功能,用户态程序(服务器对象)可访问执行体对象。 执行体对象:进程、线程、区域、文件、事件、事件对、文件映射、互斥、信号量、计时器、对象目录、符号连接、关键字、端口、存取令牌和终端等。
Windows 对象分类(2) (2)内核对象 内核实现的更原始的对象集合,包括:内核过程对象、异步过程调用对象、延迟过程调用对象、中断对象、电源通知对象、电源状态对象、调度程序对象等。 内核对象对用户态代码是不可见的,仅在执行体内创建和使用,许多执行体对象包含一个或多个内核对象,而内核对象能提供仅能由内核来完成的基本功能。
Windows 对象分类(3) Windows 对象结构 • 对象头 • 对象体 • 对象管理器
访问令牌 虚拟地址空间描述符 进程 VAD VAD VAD VAD 对象句柄表 可用对象 文件x 句柄1 区域 z 句柄 2 信号量 y 句柄 3 … 线程 线程 线程 进程及控制和使用的资源
应用程序 句柄 用户态 核心态 执行体对象 执行体 内核对象 内 核 对象和句柄间的关系
EPROCESS … void *UniqueprocessId; … KPROCESS NT内核 … uint32 kernelTime; uint32 UserTime; … byte State; … NT执行体 进程对象(进程描述表结构)
线程对象(进程和线程描述表结构) EPROCESS KPROCESS ETHREAD KTHREAD KTHREAD NT内核 KTHREAD KTHREAD KTHREAD NT执行体
调用CreateProcess函数创建进程 创建WIN32进程的具体步骤: •打开将在进程中被执行的映像文件(.EXE)。 •创建Windows2000/XP执行体进程对象。 •创建初始线程(堆栈、描述表、执行体线程对象)。 •通知WIN32子系统已创建了一个新的进程,以便它可设置新的进程和线程。 •启动初始线程的执行。 •在新进程和线程的描述表中完成地址空间的初始化,加载所需的DLL,并开始程序的执行
调用CreateThread函数创建线程 创建WIN32线程的具体步骤: •在进程地址空间内为线程创建用户态堆栈;初始化线程描述表; •调用NtCreateThread创建执行体线程对象。包括:增加进程中的线程计数,创建并初始化执行体线程块,生成新线程ID,从非页交换区分配线程的内核堆栈,设置线程环境块TEB,设置线程起始地址和用户指定的WIN32起始地址,设置KTHREAD块,设置指向进程访问令牌的指针和创建时间; •通知WIN32子系统已创建新线程,以便设置新的进程和线程; •置新线程为准备态,把其句柄和ID返回到调用进程;调用ResumeThread,线程将被激活并调度执行。
可运行 Standby 准备态 切换 选中 抢占或时间片到 Running 运行态 Ready 就绪态 不可运行 资源 可用 事件完成 资源可用 阻塞 挂起 终止 Waiting 等待态 Transition 过渡态 Terminated 中止态 事件完成但 资源不可用 Windows进程和线程状态