信息安全系统设计基础第十二周学习总结
第十二章 并发编程
应用级并发
l 访问慢速I/O设备
l 与人交互
l 通过推迟工作以降低延迟
l 服务多个网络客户端
l 在多核机器上进行并行运算
现代操作系统提供了三种基本的构造并发程序的方法
l 进程
l I/O多路复用 //
l 线程
12.1 基于进程的并发编程
服务器创建子进程,子进程可以并发处理请求
l 基于进程的并发服务器
父子进程必须关闭它们各自的connfd拷贝
l 关于进程的优劣
共享文件表,不共享用户地址空间(进程有独立的地址空间)
优:进程不可能不小心覆盖另一个进程的虚拟存储器
劣:独立的地址空间使得进程共享状态信息变得更加困难,必须使用显式的IPC机制
12.2 基于I/O多路复用的并发编程
使用select函数,要求内核挂起进程,只有在一个或多个I/O事件发生后,才将控制返回给应用程序
描述符集合
Select有两个输入:一个称为读集合的描述符集合和该读集合的基数。Select函数会一直阻塞,直到读集合中至少有一个描述符准备好可以读。
l 基于I/O多路复用的并发事件驱动服务器
I/O多路复用可以用做并发事件驱动程序的基础。状态机就是一组状态、输入事件、转移。通常把状态机画成有向图,节点表示状态,有向弧表示转移,而弧上的括号表示输入事件。
l I/O多路复用技术的优劣
优:比基于进程的设计给了程序员更多的对程序行为的控制
一个基于I/O多路复用的事件驱动服务器是运行在单一进程上下文中的,因此每个逻辑流都能访问该进程的全部地址空间,易于共享数据
劣:编码复杂,并发粒度减小,复杂性上升
12.3 基于线程的并发编程
线程:运行在进程上下文中的逻辑流
l 线程执行模型
每个进程开始是单一线程(主线程),某一时刻创建一对等线程,对等线程会执行一段时间,然后控制传递回主线程。
线程的上下文比进程小,切换快。不是按照严格的父子层次来组织。
l 创建线程:pthread_create创建新线程,并带着一个输入变量arg,arrt参数可以改变新创建线程的默认属性。
l 终止线程:
1、 当顶层的线程例程返回时,线程会隐式的终止
2、 通过调用pthread_exit函数,线程会显示的终止
3、 某个对等线程调用Unix的exit函数
4、 另一个对等线程通过以当前线程ID参数调用ptheard_cancle函数来终止当前线程。
l 回收已终止线程的资源:线程通过调用pthresd_join函数等待其他线程终止。
l 分离线程:在任何一个时间点上,线程是可结合的或是可分离的。分离线程不能被其他线程回收或杀死。使用分离线程的例子:一个高性能web服务器可能在每次收到web浏览器的连接请求时都创建一个新的对等线程,每个对等线程都应该在它开始处理请求之前分离它自身,这样就能在它终止后回收它的存储器资源。
l 初始化线程:pthread_once.once_control变量是一个全局变量或者静态变量,总是被初始化为PTHREAD_ONCE_INIT.
12.4 多线程程序中的变量
寄存器从不共享,虚拟存储器总是共享的。
l 将变量映射到存储器
1、 全局变量:虚拟存储器的读/写区域只包含每个全局变量的一个实例,任何线程都可以引用。
2、 本地自动变量:每个线程的栈都包含它自己的所有本地自动变量实例。
3、 本地静态变量:虚拟存储器的读/写区域只包含在程序中声明的每个本地静态变量的一个实例。
12.5 用信号量同步线程
共享变量方便的同时引入了同步错误的可能性。你没办法预测操作系统是否将为你的线程选择一个正确的顺序,一些顺序会产生正确的结果,一些不会。
使用进度图将一个程序的执行模型化为状态空间中的一条轨迹线。两个临界区的交集形成的状态空间区域称为不安全区。经过不安全区的轨迹称为不安全轨迹线。
l 信号量:P(s) 和V(s)。v必须只能重启一个正在等待的线程,但P和V的定义确保了正在运行的程序绝不可能进入这样的状态。
l 使用信号量来实现互斥:将每个共享变量与一个信号量s联系起来,然后用P和V操作将相应的临界区包围起来。保护共享变量的信号量叫二元信号量,互斥锁。每条实际可运行的轨迹线都是安全的。
l 利用信号量来调度共享资源:
n 生产者——消费者问题
n 读者——写者问题
l 综合:基于预线程化的并发服务器
12.6使用线程提高并行性