当前位置:嗨网首页>书籍在线阅读

23-self-pipe技巧

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

63.5.2 self-pipe技巧

由于pselect()并没有被广泛实现,可移植的应用程序必须采用其他手段来避免当等待信号并同时调用select()时出现的竞态条件。通常会用到如下方法。

1. 创建一个管道,将读端和写端都设为非阻塞的。

2. 在监视感兴趣的文件描述符时,将管道的读端也包含在参数readfds中传给select()。

3. 为感兴趣的信号安装一个信号处理例程。当这个信号处理例程被调用时,写一个字节的数据到管道中。关于这个信号处理例程,有以下几点需要注意。

  • 在第一步中已经将管道的写端设为了非阻塞态,这是为了防止出现由于信号到来的太快,重复调用信号处理例程会填满管道空间,结果造成信号处理例程的 write()操作阻塞(因而进程本身也就阻塞了)。(对于空间已满的管道,写操作失败并没有关系,因为上一次写操作已经表明了信号的传递。)
  • 信号处理例程是在创建管道之后安装的,这是为了防止在管道创建前就发送了信号从而产生竞态条件。
  • 在信号处理例程中使用 write()是安全的,因为 write()是异步信号安全函数之一,参见表21-1。

4. 在循环中调用select(),这样如果被信号处理例程中断的话,select()还可以重新得到调用。(严格来说在这种方式下重新调用 select()并不是必须的。这只是表示我们可以通过监视readfds来检查是否有信号到来,而不是通过检查返回的EINTR错误码。)

5. select()调用成功后,我们可以通过检查代表管道读端的文件描述符是否被置于 readfds中来判断信号是否到来。

6. 当信号到来时,读取管道中的所有字节。由于可能会有多个信号到来,我们需要用一个循环来读取字节直到 read()(非阻塞式)返回 EAGAIN 错误码。将管道中的数据全部读取完毕后,接下来就执行必要的操作以作为对发送的信号的回应。

这项技术通常被称为是self-pipe,程序清单63-9中的代码展示了这种技术的用法。

同样可以采用poll()和epoll_wait()来作为这种技术的变种。

程序清单63-9:采用self-pipe技巧