c++ select实现进程/线程阻塞,并设置超时时间。

select 是一个系统调用,用于多路复用 I/O 操作。它允许程序监视多个文件描述符,等待其中之一变得可读、可写或发生异常,然后执行相应的操作。select 的基本原理是将一组文件描述符传递给内核,内核会监视这些文件描述符的状态,并在有事件发生时通知应用程序。

下面是 select 函数的基本原型:

#include <sys/select.h>

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
  • nfds: 需要检查的文件描述符的数量,通常设置为待监视的最大文件描述符加 1。
  • readfds: 用于监视是否有数据可读的文件描述符集合。
  • writefds: 用于监视是否可以写入数据的文件描述符集合。
  • exceptfds: 用于监视是否有异常情况的文件描述符集合。
  • timeout: 设置超时时间,如果为 NULLselect 将一直等待直到有事件发生。

select 函数的工作流程如下:

  1. 程序调用 select 函数,并传递需要监视的文件描述符集合。
  2. 内核检查这些文件描述符,看是否有可读、可写或异常情况。
  3. 如果有事件发生,select 返回一个大于 0 的整数,表示发生事件的文件描述符的数量。
  4. 如果超时,select 返回 0。
  5. 如果发生错误,select 返回 -1,并设置 errno

在文件描述符集合中,FD_SET 用于将文件描述符添加到集合中,FD_CLR 用于将文件描述符从集合中移除,FD_ISSET 用于检查文件描述符是否在集合中。

下面是一个简单的使用 select 的示例:

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

int main() {
    fd_set readfds;
    FD_ZERO(&readfds);
    FD_SET(STDIN_FILENO, &readfds);  // 监视标准输入

    struct timeval timeout;
    timeout.tv_sec = 5;
    timeout.tv_usec = 0;

    int result = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &timeout);

    if (result > 0) {
        if (FD_ISSET(STDIN_FILENO, &readfds)) {
            // 标准输入有数据可读
            char buffer[256];
            fgets(buffer, sizeof(buffer), stdin);
            printf("Input: %s", buffer);
        }
    } else if (result == 0) {
        // 超时
        printf("Timeout
");
    } else {
        perror("select");
        exit(EXIT_FAILURE);
    }

    return 0;
}

这个示例中,程序监视标准输入是否有数据可读,如果在 5 秒内有输入,就会读取并打印输入内容;如果超时,输出 “Timeout”;如果发生错误,输出错误信息。