当线程A关闭套接字对的末尾时,为什么windows select()并不总是通知线程B的select()?

Jer*_*ner 6 c windows select multithreading stdin

我在Windows XP(SP3)下遇到的情况让我疯狂,而且我已经到了我的系绳的末端,所以也许有人可以提供一些灵感.

我有一个C++网络程序(非GUI).该程序用于在Windows,MacOS/X和Linux下编译和运行,因此它使用select()和非阻塞I/O作为其事件循环的基础.

除了网络功能外,该程序还需要从stdin读取文本命令,并在stdin关闭时正常退出.在Linux和MacOS/X下,这很容易 - 我只是在我的read fd_set中包含STDIN_FILENO来select(),而select()在stdin关闭时返回.我检查FD_ISSET(STDIN_FILENO,&readSet)是否为真,尝试从stdin读取一些数据,recv()返回0/EOF,所以我退出进程.

另一方面,在Windows下,您无法选择STDIN_FILE_HANDLE,因为它不是真正的套接字.您也不能对STDIN_FILE_HANDLE执行非阻塞读取.这意味着无法从主线程读取stdin,因为ReadFile()可能无限期地阻塞,导致主线程停止提供其网络功能.

没问题,我说,我只会产生一个线程来处理stdin.该线程将在无限循环中运行,在ReadFile(stdinHandle)中阻塞,并且只要ReadFile()返回数据,stdin线程就会将该数据写入TCP套接字.该套接字的另一端将由主线程选择(),因此主线程将看到通过连接进入的stdin数据,并以与其他任何操作系统相同的方式处理"stdin".如果ReadFile()返回false以指示stdin已关闭,则stdin-thread仅关闭其套接字对的结尾,以便主线程将通过select()通知,如上所述.

当然,Windows不会有一个很好的socketpair()函数,所以我不得不推出自己用听(),连接(),并接受()(如见于CreateConnectedSocketPair()函数在这里,但我做到了一般而言,它似乎有效.

问题是它不能100%工作.特别是,如果stdin在程序启动的几百毫秒内关闭,大约一半时间主线程没有得到任何关于套接字对的stdin-end已经关闭的通知.我的意思是,我可以看到(通过我的printf() - 调试)stdin线程在其套接字上调用closesocket(),我可以看到主线程是select() - 关联socket(即套接字对的另一端),但是select()永远不会返回......如果它确实返回,由于某些其他套接字选择了ready-for-whatever,FD_ISSET(main_thread_socket_for_socket_pair,&readSet)返回0,好像连接没有关闭.

在这一点上,我唯一的假设是Windows的select()实现中存在一个错误,导致主线程的select()没有注意到套接字对的另一端已被stdin-thread关闭.有另一种解释吗?(请注意,此问题已在Windows 7下报告,尽管我没有在该平台上亲自查看过它)

Jer*_*ner 1

郑重声明一下,这个问题完全是一个不同的问题,与线程、Windows 或 stdin 无关。实际问题是进程间死锁,父进程被阻塞,等待子进程退出,但有时子进程会同时被阻塞,等待父进程向它们提供一些数据,所以什么也不会发生。前进。

向大家致歉,因为您在转移注意力的事情上浪费了时间;如果有一种标准方法可以以无根据的方式结案,请告诉我,我会这样做。

-杰里米