20145234黄斐《信息安全系统设计基础》第十三周学习总结

课程内容总结

并发:逻辑控制流在时间上是重叠的

基于进程的并发编程

例如:在父进程中接受客户端请求,然后创建新的子进程来为每个客户端服务。

  • 假设我们有两个客户端和一个服务器,服务器正在监听一个监听表述符上的请求。现在假设服务器接受了客户端1的连接请求。
  • 基于进程的并发服务器:
    1. 需要包括一个SIGCHID处理程序,来收回将死进程。
    2. 父子进程必须关闭它们各个的connfd拷贝。
    3. 因套接字的文件表项中的引用计数,直到父子进程的connfd都关闭了,到客户端的连接才会终止。

基于I/O多路复用的并发编程

  • 使用select函数,要求内核挂起进程,只有在一个或多个I/O事件发生后,才将控制返回给应用程序。
  • select函数处理类型为fd_set的集合,也叫做描述符集合,并在逻辑上描述为一个大小为n的位向量:b_n-1,...b_1,b_0*

  • 描述符:

    1. 分配他们
    2. 将一个此种类型的变量赋值给另一个变量
    3. 用FD_ZERO、FD_SET、FD_CLR和FD_ISSET宏指令来修改和检查它们
  • 基于I/O多路复用的并发事件驱动服务器

    1. 比基于进程的设计给了程序员更多的对程序行为的控制。

    2. 一个基于I/O多路复用的事件驱动服务器是运行在单一进程上下文中的,因此每个逻辑流都能访问该进程的全部地址空间。,使得在流之间共享数据变得容易。

    3. 事件驱动设计常常比基于进程的设计要高效得多,因为它们不需要进程上下文切换来调度新进程。

基于线程的并发进程

  • 这是上面两种方法的混合,结合了上面两种方法的特性。

    1. 和进程一样,由内核调度,并内核通过一个整数ID来识别线程。
    2. 同基于I/O多路复用的流一样,多个线程运行在单一进程的上下文中。因此共享这个进程的虚拟地址空间的整个内容:代码啊,数据,堆,共享库和打开文件。
  • 线程就是运行在进程上下文中的逻辑流。
  • 每个线程都有自己的线程上下文,包括:

    1. 一个唯一的整数线程ID
    2. 栈指针
    3. 程序计数器
    4. 通用目的寄存器
    5. 条件码
  • 所有运行在一个进程里的线程共享该进程的整个虚拟地址。
  • 主线程:每个进程开始生命周期时都是单一线程,这个线程称为主线程,它是是进程中第一个运行的线程。
  • 对等线程:被主线程创建,后与主线程并发运行。
  • 对等(线程)池:一个线程可以杀死它的任何对等线程,或等待它的任何对等线程终止。每个对等线程都能读写相同的共享数据。
  • Posix线程:线程代码和本地数据都被封装在一个线程例程中。每个线程都以一个通用指针作为输入,并返回一个通用指针。
  • 创建线程:线程调用pthread_create函数来创建其他线程。
  • 终止线程

    1. 顶层的线程返回,隐式终止。
    2. 调用pthread_exit函数,显示终止。(会等待所有其他对等线程终止,然后再终止主线程和整个进程,返回thread return)
    3. 某个对等线程调用Unix的exit函数,该函数终止进程以及所有与该进程相关的线程。
    4. 另一个对等线程以当前线程ID作为参数调用pthread_cancle终止当前进程。
  • 线程调用pthread_join函数等待其他线程终止。这个函数会阻塞,直到线程tid终止,将线程例程返回的(void*)指针赋值为thread_return指向的位置,然后回收已终止线程占用的所有存储器资源.
  • 分离线程:在任何一个时间点上,进程是可结合的或分离的。
  • 初始化进程:调用pthread_once来初始化与线程的相关状态;

多线程程序中的共享变量

  • 根据存储类型被映射到虚拟存储器。
  1. 全局变量。函数以外的变量。运行时,虚拟存储器的读/写区域只包含每个全局变量的 一个实例,任何线程可用。
  2. 本地自动变量定义在函数内部没有static属性的变量。运行时,每个线程都含有自己的所有本地自动变量实例
  3. 本地静态变量。在函数内部,有static。和全局变量一样,虚拟存储器的读/写区域只包含在程序中声明的本地静态变量的一个实例。
  • 共享变量:说一个变量v是共享的,当且仅当它的一个实例被一个以上的线程引用。
  • 进度图

    进度图是将n个并发线程的执行模型化为一条n维笛卡尔空间中的轨迹线。

    将指令执行模型为一种状态到另一种状态的转换。

    合法转换:向右或向上。

    点(L1,S2)对应线程完成L1,而线程2完成S2状态

  • 信号量:是用信号量解决同步问题,信号量s是具有非负整数值的全局变量,有两种特殊的操作来处理,称为P和V:

    1. P(s):如果s非零,那么P将s减1,并且立即返回。

    2. V(s):V操作将s加1,并重启一个阻塞的线程

  • 使用信号量来实现互斥:将每个共享变量(或者一组相关的共享变量)与一个信号量s(初始为1)联系起来,然后用P(s)和V(s)操作将相应的临界区包围起来。
  • 利用信号量来调度共享资源
    1. 生产者-消费者问题:因为插入和取出项目都涉及更新共享变量,所以要保证:对缓冲区的访问是互斥的。

    2. 读者-写者问题:修改对象的线程叫做写者;只读对象的线程叫做读者。写者必须拥有对对象的独占访问,而读者可以和无限多个其他读者共享对象。

  • 基于预防线程话的并发服务器
  • 使用线程提高并行性:多核处理可以并行。

其他并发问题

  • 不安全函数类

    1. 不保护共享变量的函数
    2. 保持跨越多个调用的状态的函数
    3. 返回指向静态变量的指针的函数
    4. 调用线程不安全函数的函数
  • 可重入函数:被多个线程调用时,不会引用任何共享数据。(是线程安全函数的一个真子集)
    1. 显式可重入的:所有函数参数都是传值传递,没有指针,并且所有的数据引用都是本地的自动栈变量,没有引用静态或全剧变量。

    2. 隐式可重入的:调用线程小心的传递指向非共享数据的指针。

  • 竞争: 程序员假定线程会按照某种特殊的轨迹穿过执行状态空间,忘了一条准则规定:线程化的程序必须对任何可行的轨迹线都正确工作。
  • 死锁:一组线程被阻塞了,等待一个永远也不会为真的条件。

posted @ 2016-12-11 20:29  20145234黄斐  阅读(158)  评论(1编辑  收藏  举报