用什么在内部发出 "select" 信号?
What to use to signal "select" internally?
我正在设计一个在 Linux 上运行的机器人,我想要一个来自在 TCP/IP 上运行的机器人的仅遥测接口,主要用于我自己的 TCP 教育,但也用于保证数据包排序和校验和。我目前的设计是三个线程:
- 侦听连接并将新连接添加到
the list
的线程
- 从系统其他部分收集遥测数据并将其发送到
the list
中的每个连接的线程
select
在 the list
上的线程并删除所有与列表断开连接的客户端
我希望线程 1
能够向线程 3
发出信号“嘿伙计,新连接,更新你的列表”,对我来说显而易见的答案是创建一些额外的 file/pipe 可以添加到 3
的 select
列表中,如果附加文件是已发出信号的文件,则更新列表。我认为文件或管道对于信号来说有点矫枉过正,我认为二进制信号量可以解决问题,但我不知道如何 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()
当可读时 - 基本上,在一个线程中完成所有事情而不是试图将它分开更容易。 收集 来自机器人遥测的数据可能适合单独的线程。或者它可以在处理最终接收数据的客户端的同一个服务器中完成。你没有提供足够的信息来真正说出来。
我正在设计一个在 Linux 上运行的机器人,我想要一个来自在 TCP/IP 上运行的机器人的仅遥测接口,主要用于我自己的 TCP 教育,但也用于保证数据包排序和校验和。我目前的设计是三个线程:
- 侦听连接并将新连接添加到
the list
的线程
- 从系统其他部分收集遥测数据并将其发送到
the list
中的每个连接的线程
select
在the list
上的线程并删除所有与列表断开连接的客户端
我希望线程 1
能够向线程 3
发出信号“嘿伙计,新连接,更新你的列表”,对我来说显而易见的答案是创建一些额外的 file/pipe 可以添加到 3
的 select
列表中,如果附加文件是已发出信号的文件,则更新列表。我认为文件或管道对于信号来说有点矫枉过正,我认为二进制信号量可以解决问题,但我不知道如何 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()
当可读时 - 基本上,在一个线程中完成所有事情而不是试图将它分开更容易。 收集 来自机器人遥测的数据可能适合单独的线程。或者它可以在处理最终接收数据的客户端的同一个服务器中完成。你没有提供足够的信息来真正说出来。