首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

本章提要

网络应用程序、特别是服务器,经常需要并发地处理请求,以满足“服务质量(quality of service)”的要求。在第5章,我们讲述了“和并发选择(concurrency alternative)相关”的一般性设计权衡(design tradeoff)。在本章,我们将对同步事件多路分离(synchronous event demultiplexing)、多进程、多线程和同步机制作简要概述,利用这些机制,就可以实现第5章介绍过的那些设计。如果通过原始的“C层次”的并发API来开发网络应用程序,将会遇到一些常见的可移植性问题和编程方面的问题,本章也对这些问题进行了讨论。

6.1  同步事件多路分离

“同步事件多路分离器(synchronous event demultiplexer)”是OS提供的一个函数,用于在一组事件源(event source)上等待特定事件的发生。当一个或多个事件源被激活时,函数将返回至调用者。于是,调用者可以处理这些“来自多个源”的事件。通常,同步事件多路分离器被用作“反应式服务器”事件循环(event loop)的基本构件;它以一种“连续”而且“有序”的方式,对“来自客户的事件”进行检查并作出反应。

大多数操作系统都支持一个或多个“同步事件多路分离”函数,例如:

l  poll()函数[Rag93],出自System V UNIX;

l  WaitForMultipleObjects()函数[Sol98],由Win32提供;

l  select()函数[Ste98],在I/O句柄上对事件源进行多路分离1。

我们将重点讨论select(),因为它最常见。在事件驱动型(event-driven)网络应用程序中,可以运用select(),确定I/O操作可以在哪些句柄上同步调用,但不会阻塞那些发起这些调用的应用程序线程。select()函数的C API版本大致如下所示:

int select (int width,           // Maximum handle plus 1

            fd_set *read_fds,     // Set of "read" handles

            fd_set *write_fds,    // Set of "write" handles

            fd_set *except_fds,   // Set of "exception" handles

            struct timeval *timeout);// Time to wait for events

fd_set是一个结构,表示一组句柄(一个句柄集),用于检查I/O事件。三个fd_set地址参数分别是read_fds、write_fds和except_fds;select()分别检查它们,看它们的句柄是否处于“读”、“写”活动状态,或处于“异常条件”(例如,带外数据(out-of-band data))。select()函数通过修改它的fd_set参数,向调用者通知“活动”和“非活动”句柄的情况。

l  在fd_set中,如果一个句柄值是“非活动”的,那个句柄将被忽略;在select()返回的fd_set中,它的值将是“非活动”的。

l  如果fd_set中的一个句柄值是“活动”的,则select()将会在相应的句柄上检查是否有未处理的事件。如果在这个句柄上有一个未处理事件,则在select()返回的fd_set中,相应的值将是“活动”的。如果这个句柄没有未处理事件,则在返回的fd_set中,它的值将是“非活动”的。

每一个OS平台都会提供一组基本操作,允许应用程序“查询”、“操纵”fd_set。这些操作虽然在某些平台上是宏(macro),在另外一些平台上是函数,但它们具有一组统一的名称和行为:

 

函    数

说    明

FD_ZERO()

将fd_set中所有句柄的值标记为“非活动”

FD_CLR()

将fd_set中的一个句柄标记为“非活动”

FD_SET()

将fd_set中的一个句柄标记为“活动”

FD_ISSET()

检测fd_set中某一句柄是否“活动”

select()的最后一个参数是一个“指向struct timeval”的指针;这个结构包含以下两个字段:

struct timeval

{

  long tv_sec;  /* seconds */

  long tv_usec; /* microseconds */

};

以下三种timeval值可以传给select(),以控制“超时”行为:

行    为

NULL timeval指针

表示select()应该无限期等待,直至至少有一个I/O事件发生,或有一个信号中断了这个调用

非NULL timeval指针,tv_sec和tv_usec字段为0

表示select()应该执行“轮询(poll)”,即,检查所有句柄,并立即返回所有结果

tv_sec或tv_usec字段 > 0的timeval

表示select()应该在这段时间上等待I/O事件发生

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论