[CSAPP笔记][第十二章并发编程]

第十二章 并发编程

如果逻辑控制流在时间上是重叠,那么它们就是并发的(concurrent)。这种常见的现象称为并发(concurrency)

  • 硬件异常处理程序,进程和Unix信号处理程序都是大家熟悉的例子。

我们主要将并发看做是一种操作系统内核用来运行多个应用程序的机制。

  • 但是,并发不仅仅局限于内核。它也可以在应用程序中扮演重要的角色。

    • 例如

      • Unix信号处理程序如何允许应用响应异步事件
        • 例如:用户键入ctrl-c
        • 程序访问虚拟存储器的一个未定义的区域
    • 其他情况

      • 访问慢速I/O设备

        • 当一个应用程序正在等待来自慢速I/O设备(例如磁盘)的数据到达时,内核会运行其他进程,使CPU保持繁忙。
      • 与人交互

        • 和计算机交互的人要求计算机有同时执行多个任务的能力。
      • 通过推迟工作以降低延迟

        • 有时,应用程序能够通过推迟其他操作和并发执行它们,利用并发来降低某些操作的延迟
      • 服务多个网络客户端
        • 一个慢速的客户端可能会导致服务器拒绝为所有客户端提供服务。
      • 在多核机器上进行并行运算

使用应用级并发的应用程序称为并发程序(concurrent program).

  • 操作系统提供三种基本的构造并发程序的方法:

    • 进程

      • 每个逻辑控制流 都是一个进程

        • 由内核来调度和维护。
      • 因为进程有独立的虚拟地址空间

        • 和其他进程通信,控制流必须使用某种显式的进程间通信(interprocess communication,IPC)进制
    • I/O多路复用(暂时不太懂)
      • 应用程序在一个进程的上下文中显示地调度它们自己的逻辑流
      • 逻辑流被模型化为状态机,数据到达文件描述符后,主程序显式地从一个状态转换到另一个状态。
      • 因为程序是一个单独的进程,所以所有的流都共享同一个地址空间。
    • 线程
      • 线程是运行在一个单一进程上下文中的逻辑流,有内核调度。
        • 进程一样由内核进行调度。
        • 而像I/O多路复用一流一样共享一个虚拟地址空间。

12.1 基于进程的的并发编程

一个构造并发服务器的自然方法就是,在父进程中接收客户端连接请求,然后创建一个新的子进程来为每个新客户端提供服务。

  • 服务器正在监听一个监听描述符(描述符3)上的连接请求
  • 服务器接收客户端1的连接请求
  • 并返回一个已连接描述符(描述符4)。

  • 子进程获得服务器描述符表的完整拷贝(描述符3,4)
  • 子进程关闭它的拷贝中的监听描述符3
  • 服务器关闭描述符表中的描述符4

  • 之后新的客户端又类似之前两个步骤。

12.1.1 基于进程的并发服务器

  • Signal(SIGCHLD,sigchld_handler)回收僵死进程。

    • 具体细节见8.5.7
  • 28行,33行 父子进程各自关闭他们不需要的拷贝。

  • 因为文件表项的引用计数,直到父进程关闭它的描述符,才算结束一次连接

12.1.2 关于进程的优劣

对于在父,子进程间共享状态信息,进程有一个非常清晰的模型

  • 共享文件表,但是不共享用户地址空间
  • 进程拥有独立的虚拟地址空间即是 优点,也是 缺点

    • 优点:一个进程不可能不小心覆盖另一个进程的虚拟存储空间。

      • 消除许多令人迷惑的错误。
    • 缺点:独立的地址空间使得进程间共享信息也很困难。

      • 必须使用显式的IPC(进程间通信)机制。

      • 往往还比较

        • 进程控制IPC的开销都很大。

12.2 基于I/O多路复用的并发编程(暂时跳过)

假设要编写一个echo服务器

  • 服务器既能响应客户端的请求
  • 也能对用户从标准输入输出的交互命令做出反应(如exit).

因此,服务器必须要响应两个相互独立的I/O事件

  • 网络客户端发起连接
  • 用户在键盘键入命令行。

无论先等待那个事件都不是理想的,解决办法之一是就是使用I/O多路复用技术

  • 基本的思路
    • 使用select函数,要求内核挂起进程,只有一个或多个I/O事件发生后,才将控制返回给应用程序。

12.3 基于线程的并发编程

线程(thread) 就是运行在进程上下文中的逻辑流。

  • 线程由内核调度。
  • 每个线程都有它自己的线程上下文(thread context).

    • 包括一个唯一的整数线程ID(Thread ID,TID).
    • 栈和栈指针
    • 程序计数器
    • 通用目的寄存器和条件码
  • 所有运行在该进程里的线程共享该进程的整个虚拟地址空间。

    • 共享 包括代码,数据,堆,共享库和打开的文件。

12.3.1 线程执行模型

  • 每个进程开始生命周期时都是单一线程,这个线程称为主线程(main thread)

    • 某时刻,主线程创建一个对等线程(peer thread)
      • 当主线程执行一个慢速系统调用,例如readsleep
      • 或者被系统的间隔计时器中断。
      • 控制就会通过上下文切换传递到对等线程
      • 对等线程执行一段时间,将控制传递回主线程。
  • 在某些方面,线程执行是不等同于进程的。

    • 线程的上下文切换的开销比进程的小得多,快得多
    • 线程不是按照严格的父子层次来组织。
      • 和一个进程相关的线程组成一个线程池(pool)
        • 线程池概念的主要影响是
        • 一个线程可以杀死它的任何对等线程,或等待任意对等线程终止。
        • 每个对等线程都能读写相同的共享数据。

1

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值