##CSAPP读书日记-第十二章-并发编程

一、应用级并发的作用

在这里插入图片描述

构造并发程序的方法:

在这里插入图片描述
在这里插入图片描述

二、基于进程的并发编程

构造并发程序最简单的方法就是用进程,使用像fork、exec和waitpid之类的函数。

特点:

父子进程之间共享文件表,但是不共享用户地址空间。
优点:一个进程不会覆盖另一个进程的虚拟内存。
缺点:进程共享状态信息变得困难,必须使用显式的IPC(进程间通信)机制。
结果就是这种设计方式比较慢,因为进程控制和IPC的开销很高。

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

I/O多路复用(I/O Multiplexing)技术基本的思想就是使用select函数,要求内核挂起进程,只有在一个或者多个I/O事件发生后,才将控制返回给应用程序。

I/O多路复用可以用作并发事件驱动(event-driven)程序的基础。

在事件驱动程序中,某些事件会导致流向前推进。
一般的思路是将逻辑流模型化为状态机(state machine):

  • 它是一组状态(state)、输入事件(input-event)和转移(transition)。
  • 转移是将一个(输入状态,输入事件)对映射到一个输出状态。

通常把状态机画成有向图:
在这里插入图片描述
这种设计的优点有:

  • 它比基于进程的设计给了程序员更多的对程序行为的控制。
  • 它是运行在单一进程上下文中,因此每个逻辑流都能访问该进程的全部空间地址。这使得在流之间共享数据变得很容易。
  • 比进程设计方式要高效很多,因为它不需要进程上下文切换来调度新的流。

这种设计的缺点有:

  • 编码复杂。
  • 不能充分利用多核处理器。

现代高性能服务器(比如node.js,nginx和tornado)使用的都是基于I/O多路复用的事件驱动的编程方式,主要是因为相比于进程和线程的方式,它有明显的性能优势。

四、基于线程的并发编程

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

  • 它由内核自动调度。
  • 它有自己的线程上下文(thread context)。
  • 所有的运行在一个进程里的线程共享该进程的整个虚拟地址空间。

基于线程的逻辑流结合了基于进程和基于I/O多路复用的流的特性。

  1. 每个进程开始生命周期时都是单一线程,这个线程成为主线程(main thread)。
  2. 在某一个时刻,主线程创建一个对等线程(peer thread),从这个时间点开始,两个线程就并发地运行。
  3. 最后,因为主线程执行一个慢速系统调用,或者被系统的间隔计时器中断,控制就会通过上下文切换传递到对等线程。
    对等线程执行一段时间,然后控制传递回主线程。

线程不同于进程在于:

  • 线程的上下文很小,所以切换线程上下文比切换进程的要快得多。
  • 线程没有严格的父子层次来组织,主线程和对等线程的区别仅在于它是进程中第一个运行的线程。
  • 一个线程可以杀死它的任何对等线程,或者等待它的任意对等线程终止。
    每个对等线程都可以读写相同的共享数据。
  • 在任意一个时间点上,线程是可结合的(joinable)或者是可分离的(detached)。
    • 一个可结合的线程能被其他线程回收和杀死,在被回收之前,它的内存资源不会释放。
    • 一个分离的线程是不能被其他线程回收或杀死的。它的内存资源在它终止时由系统自动释放。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/zjx130/article/details/87544066