信息安全系统设计基础第十二周学习总结
第十二章 并发编程
并发指逻辑控制流在时间上是重叠的
进程:
- 每个控制流都是一个进程
- 是由内核来调度维护
- 有独立的虚拟地址空间
- 在与其他流进行通信时,控制流必须使用某种显式的进程间通信机制
I/O多用复路: - 在并发编程中,应用程序在一个进程的上下文中显式的调度它们自己的逻辑流
- 所有流都共享同一个地址空间
线程: - 是运行在单一进程上下文中的逻辑流
- 由内核进行调度
- 是进程和I/O多用复路的混合体
基于进程的并发编程
基于进程的并发服务器
由于服务器运行时间长,所以要包括一个SIGCHLD进程程序,用来回收僵死子进程的资源
关于进程的优劣
对于父,子进程:共享文件表,但不共享用户地址空间
基于I/O多用复路的并发编程
基本思路:使用select函数,要求内核挂起进程,只有在一个或多个I/O事件发生后,才将控制返回应用的程序
例如:
select函数处理类型为fd_set的集合
被允许对描述符集合做的三件事:
- 分配他们
- 将一个此种类型的变量赋值给另一个变量
- 用FD_ZERO,FD_SET,FD_CLR和FD_ISSET宏指令来修改和检查他们
select的两个输入: - 读集合的描述输入(fdset)
- 读集合的基数(n)
副作用:select修改了参数fdset指向的fd_set,指明读集合中一个称为准备好集合的子集
利用select实现一个迭代echo服务器:
一旦select返回,就用FD_ISSET宏指令来判断哪个可以进行读了
基于I/O多用复路的并发事件驱动服务器
一个状态机就是一组状态,输入事件和转移,其中转移就是将状态和输入事件映射到状态
自循环同一个输入和输出之间的转换
- select函数检测到输入事件
- add_client函数创建一个新的逻辑流
- check_clients函数通过回送输入行来执行状态转移
服务器使用I/O多用复,借助select函数检测输入事件的发生
clientfd数组表示已连接描述符的集合,其中整数-1表示一个可用的槽位
I/O多用复路技术的优劣:
优点:
- 它比基于进程的设计给程序员更多的对程序行为的控制
- 一个基于I/O多用复路用事件驱动服务器是运行在一个单一进程上下文,并每个逻辑流都能访问该进程的全部地址空间
缺点:
- 编码复杂
基于线程的并发编程
每个线程都有它自己的线程上下文,包括一个唯一的整数线程ID,栈,栈指针,程序计数器,通用目的寄存器和条件码
线程执行模型
主线程:每个进程开始生命周期都是单一线程
某时刻,主线程创建一个对等线程,从此时开始,两个线程并发运行
线程和进程的区别:
- 一个线程的上下文比一个进程的上下文小很多
- 线程上下文的切换要比进程上下文的切换快很多
- 进程是按照严格的父子层次来组织的,线程则是对等的池
Posix线程
-
创建线程
-
终止线程
- 当顶层的线程例程返回时,线程会隐式地终止
- 通过调用pthread_exit函数,线程会显式地终止
- 某个对等线程调用Unix的exit函数,该函数终止进程以及与该进程相关的所有线程
- 另一个对等线程通过当前线程ID作为参数调用pthread_cancle函数来终止当前线程
-
回收已终止线程的资源
pthread_join函数会堵塞,直到线程tid终止,将线程例程返回的(void)指针赋值为pthread_return指向的位置,然后回收*已终止线程占用的所有储存器资源 -
分离线程
在任意一个时间点上,线程是可结合的或者是分离的
-
初始化线程
多线程程序中的共享变量
通常,线程的寄存器是从不共享的,而虚拟储存器总是共享的
将变量映射到存储器
- 全局变量:是定义在函数之外的变量,任何线程都可以引用
- 本地自动变量:是定义在函数内部但是没有static属性的变量
- 本地静态变量:是定义在函数内部并有static属性的变量
共享变量
若说变量v是共享的,当且仅当它的一个实例被一个以上的线程引用
用信号量同步线程
在共享变量的同时引入了同步错误的可能性
一般而言,没有办法预测操作系统是否能为你的线程选择一个正确的顺序
进度图
进度图将n个并发线程的执行模型化为一条n维笛卡尔空间中的轨迹线
图的原点对应于没有任何线程完成一条指令的初始状态
在进度图中,两个临界区的交集形成的状态空间区域称为不安全区
信号量
- P(s):如果s是非零的,那么P将s减1,并且立即返回。若s为零,则挂起这个线程,直到s非零
- V(s):V操作将s加1
使用信号量来实现互斥
基本思想:将每个共享变量与一个信号量s联系起来,然后用P(s)和V(s)操作将相应的临界区包围起来
利用信号量来调度共享资源
生产者-消费者问题
基于预线程化的并发服务器
使用线程提高并行性
最简单的方法:将序列划分成t个不相交区域,然后给t个不同的线程每个分配一个区域
并行程序的加速比:
其他并发问题
线程安全
四个线程不安全函数类:
- 不保护共享变量的函数
- 保持跨越多个调用的状态的函数
- 返回指向静态变量指针的函数
- 调用线程不安全函数的函数
可重入性
在线程化的程序中使用已存在的函数库
竞争
当一个程序的正确性一个线程要在另一个线程到达y点之前到达它的控制流中的x点时,就会发生竞争
死锁
避免死锁的规则:
互斥锁加锁顺序规则:如果对于程序中每对互斥锁(s,t),每个同时占用s和t的线程都按照相同的顺序对它们加锁,那这个程序是无死锁的