用什么在内部发出 "select" 信号?

What to use to signal "select" internally?

我正在设计一个在 Linux 上运行的机器人,我想要一个来自在 TCP/IP 上运行的机器人的仅遥测接口,主要用于我自己的 TCP 教育,但也用于保证数据包排序和校验和。我目前的设计是三个线程:

  1. 侦听连接并将新连接添加到 the list
  2. 的线程
  3. 从系统其他部分收集遥测数据并将其发送到 the list
  4. 中的每个连接的线程
  5. selectthe list 上的线程并删除所有与列表断开连接的客户端

我希望线程 1 能够向线程 3 发出信号“嘿伙计,新连接,更新你的列表”,对我来说显而易见的答案是创建一些额外的 file/pipe 可以添加到 3select 列表中,如果附加文件是已发出信号的文件,则更新列表。我认为文件或管道对于信号来说有点矫枉过正,我认为二进制信号量可以解决问题,但我不知道如何 select 在二进制信号量上。

我想我的问题是:你认为可以将文件描述符转换成文件描述符以便可以 select 处理它们吗?

我的第二个问题是:我是一名“老派”Linux/C 开发人员,他们正在尝试跟上更现代的技术,特别是现代 c++,是否有更“现代 c++”的方法来做到这一点?

eventfd(2) 是一种方便的 Linux-specific API ,用于此类通知。它创建一个文件描述符,可用于通过写入来发出事件信号。

使用它的示例(和 poll(),通常优于 select()):

#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <thread>

#include <unistd.h>
#include <poll.h>
#include <sys/eventfd.h>

void messenger(int efd) {
  while (1) {
    std::uint64_t i = 1;
    if (write(efd, &i, sizeof i) != sizeof i) {
      std::perror("write");
      std::exit(1);
    }
    sleep(1);
  }
}

int main() {
  int efd = eventfd(0, 0);
  if (efd < 0) {
    std::perror("eventfd");
    return 1;
  }
  std::thread messenger_thread{messenger, efd};
  struct pollfd waiter[1];

  waiter[0].fd = efd;
  waiter[0].events = POLLIN;
  
  while (poll(waiter, 1, -1) >= 0) {
    if (waiter[0].revents & POLLIN) {
      std::uint64_t i;
      if (read(efd, &i, sizeof i) != sizeof i) {
        std::perror("read");
        return 1;
      }
      std::puts("Signaled by messenger.");
    }
  }
}

不过,正如我之前的评论所述,我认为这是错误的架构——你真的不应该有另一个线程来检测关闭的连接,因为这些连接通常是通过套接字上的读取或写入失败发出的- 最好在向它们发送数据的同一个线程中完成。并且很容易有一个 non-blocking 监听套接字,你也可以轮询它和 accept() 当可读时 - 基本上,在一个线程中完成所有事情而不是试图将它分开更容易。 收集 来自机器人遥测的数据可能适合单独的线程。或者它可以在处理最终接收数据的客户端的同一个服务器中完成。你没有提供足够的信息来真正说出来。