在可用写入 fdset 上选择阻塞,直到进程中断并续订
Select blocking on available write fdset until the process is interrupted and renewed
我有一个TCP服务器应用程序和一个TCP客户端应用程序。服务器在多个线程中运行,在一个线程中,select() 调用以无限期超时阻塞:
while(running) {
initFdSets();
nfds = select(max_fd + 1, &listened_fdset, &write_fdset, &exception_fdset, NULL);
...
reads_from_fds_in_listened_fdset();
writes_to_fds_in_write_fdset();
}
同时,在另一个线程中,首次将有效的套接字文件描述符添加到写入 FD 集中:
FD_SET(connection_socket_fd, write_fdset_ptr);
并且 select() 调用仍然阻塞。 在此期间,客户端应用会阻止想要从两者之间连接的另一端读取的 read() 调用:
read(sockfd, &msgType, sizeof(int32_t));
直到我在调试模式下中断服务器应用程序然后恢复它之前,什么都不会发生。这样做之后,select() 返回,将适当的字节流发送到客户端应用并按计划接收。Writefdset 在 select() 调用之前重新初始化...但是服务器行为在新的 while() 迭代中不会改变。
是的,所有集合都使用 FD_ZERO 清除并在调用 select() 之前重新初始化(包括第二个代码段中的文件描述符)。
我会感谢这个问题的解决,因为这是我必须从我的项目中摆脱的最后一个问题 - 但不知道它是如何以及为什么发生的。
查看手册页,以便在此处选择:选择手册页。
选择挂起的原因是您需要将 timeval 作为参数传递给它,以便告诉它应该超时。引用:
The timeout
The time structures involved are defined in <sys/time.h> and look
like
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
and
struct timespec {
long tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
(However, see below on the POSIX.1 versions.)
Some code calls select() with all three sets empty, nfds zero, and a
non-NULL timeout as a fairly portable way to sleep with subsecond
precision.
On Linux, select() modifies timeout to reflect the amount of time not
slept; most other implementations do not do this. (POSIX.1 permits
either behavior.) This causes problems both when Linux code which
reads timeout is ported to other operating systems, and when code is
ported to Linux that reuses a struct timeval for multiple select()s
in a loop without reinitializing it. Consider timeout to be unde‐
fined after select() returns.
因此,这应该可以解决您的问题:
while(running) {
timeval tv = {};
static constexpr long myTimeoutInMicros = 10000; // Put your desired timeout here.
tv.tv_usec = myTimeoutInMicros;
tv.tv_sec = 0;
initFdSets();
nfds = select(max_fd + 1, &listened_fdset, &write_fdset, &exception_fdset, &tv);
...
reads_from_fds_in_listened_fdset();
writes_to_fds_in_write_fdset();
}
我还建议使用beej的网络指南进行额外的阅读:Beejs网络指南,这是bsd风格的套接字呼叫网络的综合来源。
编辑:值得注意的是,在 Solaris 10/Solaris 11(不确定 IlumOs)上,无论是否提供 timeval,选择都将超时。
相关文章:
- boost::进程间消息队列引发错误
- 在进程中对同一管道进行读取和写入时C++管道出现问题
- 是否可以通过C++扩展强制多个python进程共享同一内存
- IPC使用多个管道和分支进程来运行Python程序
- 异常属于C++中的线程还是进程
- WMI检测进程创建事件-c++
- c++多进程编写一个唯一的文件
- 如何在C++中将函数发送到另一个进程
- 在Qt Creator中,如何在连接到正在运行的进程后查看控制台输出
- 类成员和中断
- 捕获标准输出以压缩并使用 CTRL-C 中断会给出损坏的 zip 文件
- 终止 QProcess 不会终止子进程
- 将返回值从 exe 传递到 bat,并将其传递给 C# 中的进程
- COM :是否可以查看是否存在对我的某个 COM 对象的进程外引用?我可以释放它吗?
- 在可用写入 fdset 上选择阻塞,直到进程中断并续订
- 进入子进程时 GDB 中断
- 中断 arduino 例程以运行基于延迟的慢速进程
- 无法中断执行.此进程当前未执行该类型的代码
- 如何在Linux应用程序上使用C++中的终端输入中断循环/进程
- 如果stdin被另一个进程的管道替换,Std::getline将中断