并发(Concurrency)是多个任务或多个计算在同一时间段内发生的能力,并发的目的是允许系统更有效地使用资源,或在等待某些任务(例如,I/O操作)完成时执行其他任务。
例如,在 GUI 应用程序中,用户界面线程可以响应用户输入,而另一个线程在后台进行计算或 I/O 操作,这样用户界面不会因为后台任务的等待而冻结。
我们来阐述三个基本构造并发程序的方法:
每个逻辑控制流都可以看作是一个进程,由操作系统的内核来进行调度和管理,因为每个进程有独立的虚拟地址空间,它们之间想要通信,需要显示的使用 IPC 通信机制。
考虑这样一个场景:假设我们有两个客户端和一台服务器,服务器正在监听 3 号端口上的请求,假设现在服务器接受了客户端 1 的请求,并返回一个已连接描述符。
在接受连接请求之后,服务器生成一个子进程,这个子进程获得服务器描述符的完整副本,子进程关闭它副本中监听的 3 号描述符,同时父进程关闭其已连接的 4 号描述符,接着,子进程为客户端 1 提供服务。
因为父子进程都是指向的同一个文件表表项,所以父进程关闭它的已连接描述符的副本是很重要的,否则就永远不会释放已连接的 4 号描述符,而且由此引起的内存泄露最终消耗完所有可用内存,使系统崩溃。
之后,父进程接受一个新的客户端 2 的连接请求,并返回一个新的连接 5 号描述符。
再次,父进程又派生另一个子进程,这个子进程用已连接的 5 号描述符来为它的客户提供服务。
此时,父进程还在继续等待下一个连接请求,而两个子进程并发地为它们各自的客户端提供服务。对于父子进程间共享状态信息,有一个非常清晰的模型:共享文件描述符表,但不共享用户地址空间,由于每个进程都有独立的地址空间,每个进程的虚拟内存都是单独维护的,所以不存在相互覆盖的问题。进程间若要共享信息,必须采用 IPC 通信机制,但这种基于进程来设计的方式往往相对比较慢,因为进程控制和 IPC 通信的开销很高。在这种并发编程模式中,应用程序在单个进程的上下文中显式地调度自己的逻辑控制流。假设应用要处理两个 I/O 交互,一个是客户端发起的网络请求,一个是在键盘上输入的命令行。我们先执行哪个事件呢?传统的 I/O 操作是阻塞性的,如果我们执行命令行,那网络连接请求就需要等待;如果我们处理网络连接请求,那命令行就需要等待。I/O 多路复用提供了解决方案,使程序能够在一个进程内并发地监听多个 I/O 通道:- 将要监听的通道(套接字、命令行输入)注册到该实例上。
- 程序进入一个等待的状态,等待已经注册好的通道,并且通道准备好「读或写」操作;
- 当某个或多个 I/O 通道准备好时,多路复用系统将返回这些活跃的通道;
- 应用程序立即处理这些活跃的通道,而不必等待其他未准备好的通道;
一个单独的进程可以创建多个并发的 I/O 事件,避免创建多个进程的开销。
I/O 多路复用解决的是准备好的通道,而不是处理通道阻塞的问题(多个通道同时响应),而实际的处理(如读/写操作)仍然是顺序执行的。
在之前的方法中,我们讨论了利用「进程」来处理并发,其中每个控制流都是独立的进程,由内核调度。因为每个进程都有独立的地址空间,数据共享变得复杂,尽管有 IPC 通信,但进程间的通信开销仍然较大。
我们还探讨了 I/O 多路复用技术,它允许在单一进程中显式调度多个逻辑流,这使得数据共享变得简单,但多通道并发响应时的处理仍然是串行的,因此并发效果有限。
下面我们将介绍基于「线程」的方法,它是这以上两种方法的融合。
线程是在单一进程上下文中执行的逻辑控制流,由内核负责调度,每个线程都有自己的执行上下文,这包括线程ID、栈、栈指针、程序计数器、通用寄存器和条件码,所有属于同一个进程的线程共享该进程的全部虚拟地址空间。
每个进程启动时只有一个线程,即主线程。在其生命周期的某个时刻,主线程可以创建多个对等线程,它们并发运行,可以读写同一块共享数据。主线程主要负责监听新连接和现有连接上的 I/O 活动。启动时,主线程初始化一个线程池,其中所有线程初始状态均为闲置,等待主线程分配任务。利用 I/O 多路复用,主线程可以监听多个通道「套接字、命令行」。当出现新的连接请求或现有连接就绪时,多路复用通知主线程。对于新的连接请求,主线程自行处理,并加入到多路复用的监听集合中。一旦线程池中的工作线程被分配任务,它就开始执行相应的 I/O 操作和数据处理。分配任务后,主线程不会等待该任务完成,而是回到多路复用继续监听其他 I/O 活动。线程提供了一种高效的并发编程方法,与传统进程相比,它有以下优点:线程为并发编程提供了一种高效、灵活且经济的方法,使得开发者可以更好地管理和调度系统资源,从而满足高并发、高响应的应用需求。
内容优化:ChatGPT
内容来源:《深入理解计算机系统》
原创文章,作者:小道研究,如若转载,请注明出处:https://www.sudun.com/ask/34607.html