从socket select中跳出

9

我有一个循环,基本上每隔几秒钟(超时后)就调用这个函数:

 while(true){

    if(finished)
       return;

    switch(select(FD_SETSIZE, &readfds, 0, 0, &tv)){
        case SOCKET_ERROR : report bad stuff etc; return;
        default : break;
    }

    // do stuff with the incoming connection
 }

基本上,每隔几秒钟(由tv指定),它会重新激活监听。

这在B线程(不是主线程)上运行。有时我想从A线程(主线程)立即结束这个接受器循环,但似乎我必须等到时间间隔结束。

是否有一种方法可以从另一个线程中断选择功能,以便B线程可以立即退出?


附注:您可以删除if语句,只需编写while(!finished)。 - Björn Pollex
1
那会占用100%的CPU时间。绝对不可接受。 - kamziro
糟糕,我一定是看错了。 - kamziro
在Windows上编程 :) 你有几个选项可以异步地进行套接字I/O。例如,你可以将套接字与可等待事件(WSAEventSelect)关联起来,然后等待这些事件,以及你自定义的事件,并使用你需要的超时时间。 - valdo
4个回答

11

最简单的方法可能是使用pipe(2)创建管道,并将读取端添加到readfds。当另一个线程想要中断select()时,只需向其写入一个字节,然后在之后进行消耗。


这是一个监听套接字(用于接受连接)。这样还能工作吗?我在考虑调用一些销毁套接字的函数...看看会发生什么。这样安全吗? - kamziro
2
它正在等待一个文件。它不关心是哪一个,它只想要一些东西。 - Ignacio Vazquez-Abrams
它起作用了,我还通过Unix管道学到了一些东西!谢谢!顺便说一下,在中断之后我所做的就是退出程序。所以我不需要考虑消费。这样可以吗? - kamziro
1
应该这样做。拆除管道应该销毁其中的任何内容。 - Ignacio Vazquez-Abrams

3
是的,您可以创建一对连接的套接字。然后B线程写入套接字的一侧,A线程将另一侧的套接字添加到select中。因此,一旦B向套接字写入数据,A就会退出select,请不要忘记从套接字读取这个字节。
这是最常见和标准的中断select的方法。
注意:
在Unix下,使用socketpair来创建一对套接字,在Windows下有点棘手,但搜索Windows socketpair会给您提供代码示例。

啊,我刚刚使用了pipe(2)函数,看起来运行正常。或许以后还需要考虑它的窗口对应部分。 - kamziro

-1

你不能把超时时间设置得足够短一点吗(比如10毫秒左右)?

这种“创建一个虚假连接”的解决方案似乎有些不正规。我个人认为,如果一个应用程序设计得很好,那么并发任务就不必被强制中断,只需要工作线程经常检查即可(这也是为什么boost.threads没有终止函数的原因之一)。

编辑 将此答案标记为简历。它可能不好,但它可能会帮助其他人理解为什么它不好,这在评论中有所解释。


1
-1 这是非常糟糕的解决方案,只会浪费 CPU 资源并且仍然存在延迟问题。有标准的解决方案可供选择。 - Artyom
那会占用多少CPU资源?相比创建一个虚假的套接字连接,等待CPU 10毫秒会有什么影响? - Björn Pollex
1
CPU成本在于减少超时时间,使循环更频繁运行。 - caf
1
“虚拟”连接的优点在于写入的字节可以具有意义,因此不再需要线程共享状态(假设“完成”标志由另一个线程设置,需要一些同步,这似乎在这里缺失)。仅通过消息传递在线程之间通信并不是“hack”。需要进行一定的设置,但它可以显着简化应用程序状态模型。我并不认为强制所有内容快速轮询,而不是充分利用异步操作,完全没有任何技巧。 - Steve Jessop
即使在设计良好的应用程序中,一个线程可能会告诉另一个线程停止。这并不是强制性的,而是非常干净的,因为应该停止的线程可以进行清理等操作。类似于“KillThread”的方式是一种强制性的方法... - mmmmmmmm

-1

你可以在主线程中使用shutdown(Sock, SHUT_RDWR)调用来退出等待select调用,这也会在超时之前退出另一个线程,因此你不需要等待超时到期。

干杯。:)


1
很遗憾,您无法“关闭”一个正在监听的套接字。而且,在另一个线程正在使用它或可能正在使用它时,没有安全的方法来“关闭”它。 - David Schwartz
如果您拥有以下套接字线程函数,并且如果您从主线程发送shutdown(sock, SHUT_RD),它将唤醒在其他线程中执行的SockThreadFunction等待的select调用。我已经尝试过这个,它可以正常工作。SockThreadFunction(){ while(SocketOpen) { //正在等待Select调用 int Ready = select(pSocket->m_Sock+1, &SockSet, 0, 0, 0); } } - Harshal Chaudhary
他有一个监听套接字。你不能shutdown一个监听套接字。它可以用于已连接的套接字,但对于他所拥有的监听套接字不起作用。 - David Schwartz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接