You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何第二次调用的select()会陷入阻塞?

问题原因与修复方案

核心原因

select()调用会直接修改传入的fd_set集合,仅保留触发了事件的文件描述符。第一次select()因stdin输入触发返回后,set集合中只剩下stdin的文件描述符(0),管道读端的fd已被移除,导致第二次select()根本没有监听管道读端,自然不会因管道有数据而返回。

另外,代码中第二次select()后的read操作存在错误:误读了stdin而非管道读端。

修复步骤

  1. 每次调用select()前必须重新初始化fd_set:
    • 调用FD_ZERO()清空集合
    • 重新添加所有需要监听的文件描述符
  2. 修正read操作的目标文件描述符:从管道读端fd_pipe[0]读取数据,而非stdin。

修复后的代码

int    fd_pipe[2];
char   buf[20];
fd_set set;

pipe(fd_pipe);

// 第一次select准备
FD_ZERO(&set);
FD_SET(fd_pipe[0], &set);
FD_SET(0, &set);

select(fd_pipe[0]+1, &set, NULL, NULL, NULL);

if (FD_ISSET(0, &set))
{
    read(0, buf, 20);          
    write(fd_pipe[1], buf, 1); 
}

// 第二次select前重新初始化集合
FD_ZERO(&set);
FD_SET(fd_pipe[0], &set);
// 若无需再监听stdin,可移除FD_SET(0, &set)
FD_SET(0, &set);

select(fd_pipe[0]+1, &set, NULL, NULL, NULL);

if (FD_ISSET(fd_pipe[0], &set))
{
    char d;
    read(fd_pipe[0], &d, 1); // 修正为读取管道读端
    assert(d == buf[0]);
}

多线程场景补充

  • 确保管道文件描述符的操作线程安全,避免写入和select监听的竞态问题
  • 若仅需通过管道触发取消操作,第二次select可只监听管道读端,减少不必要的资源消耗

内容的提问来源于stack exchange,提问作者Stewart

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 11:52:47