旧游无处不堪寻
无寻处,惟有少年心
操作系统(六)

提到并发,似乎只能用线程来实现。显示情况并不是如此,一些基于图形用户界面的应用或某些类型的网络服务器,常常采用另一种并发方式,这种方式称为基于事件的并发

实现基于事件的并发很简单,我们等待事件发生,当它发生时,检查事件类型,然后做少量的相应工作( I/O 请求,或者调度其他事件准备后续处理等)。

select() 和 poll()

为了实现基于事件的并发,必须解决如何接收事件的问题。大多数系统提供了基本的 API,即通过 select() 或 poll() 系统调用。检查是否有任何应该关注的事件进入 I/O。无论哪种方式,这些基本原语为我们提供了一种构建非阻塞事件循环的方法,它可以简单地检查传入数据包,从带有消息的套接字中读取数据,并根据需要进行回复。

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int main(void) {
// open and set up a bunch of sockets (not shown)
// main loop
while (1) {
// initialize the fd_set to all zero
fd_set readFDs;
FD_ZERO(&readFDs);

// now set the bits for the descriptors
// this server is interested in
// (for simplicity, all of them from min to max)
int fd;
for (fd = minFD; fd < maxFD; fd++)
FD_SET(fd, &readFDs);

// do the select
int rc = select(maxFD+1, &readFDs, NULL, NULL, NULL);

// check which actually have data using FD_ISSET()
int fd;
for (fd = minFD; fd < maxFD; fd++)
if (FD_ISSET(fd, &readFDs))
processFD(fd);
}
}

注意: 在基于事件的系统中必须遵守一条规则不允许阻塞调用

异步 I/O

为了克服这个限制,许多现代操作系统已经引入了新的方法来向磁盘系统发出 I/O 请求,称为异步 I/O。这些接口使应用程序能够发出 I/O 请求,并在 I/O 完成之前立即将控制权返回给调用者,另外的接口让应用程序能够确定各种 I/O 是否已完成。