我有一个异步应用程序执行多个线程,在套接字上执行操作,然后异步执行操作。避免在多线程套接字应用程序中重复使用相同的fd号
我试图避免一旦调度一个套接字的读取操作时,套接字被关闭并在第一次操作开始执行之前重新打开(可能是另一个操作中的另一个对象),这将最终读取正确的文件描述符,但错误的对等体。
问题出在因为(accept(); close(); accept())在accept()中返回相同的fd会导致上述情况。
我看不到一种避免它的方法。
任何提示?
我有一个异步应用程序执行多个线程,在套接字上执行操作,然后异步执行操作。避免在多线程套接字应用程序中重复使用相同的fd号
我试图避免一旦调度一个套接字的读取操作时,套接字被关闭并在第一次操作开始执行之前重新打开(可能是另一个操作中的另一个对象),这将最终读取正确的文件描述符,但错误的对等体。
问题出在因为(accept(); close(); accept())在accept()中返回相同的fd会导致上述情况。
我看不到一种避免它的方法。
任何提示?
好的,找到答案。
这里最好的方法是调用accept()并获得最低的fd可用,使用您已知的数字(如dup2(6,1000)和close(6))复制它,您现在可以控制fd范围你用。
接下来再接受6或类似的,我们将dup2(6,999);并继续降低,如果太低,则重新设置。
由于接受在同一个线程和DUP2一直在做和关闭不贵相比,接受它总是做有它非常适合我的需求。
如何管理套接字?这听起来像你有多个线程的任何一个都可以:
accept
传入的连接close
现有连接这听起来像你需要一种方法调解进入周围浮动的各种插座。您是否考虑过将每个套接字与互斥锁相关联,以防止在套接字仍在使用时关闭套接字,或者可能将每个套接字描述符放入一个带有原子引用计数的结构中,以防止其他线程在所有线程完成使用之前关闭它?
我可以这样做,但在这个几乎无锁的系统中添加互斥体是我试图避免的。 最好的事情是保证接受不会顺序给予fd,但我看不到发生这种情况。 – 2009-10-01 15:17:25
@Arkaitz - 那么我提到的第二个解决方案可能对你有好处。将套接字保存在带有引用计数器的结构中,并且不要让任何线程关闭具有大于零的引用计数的套接字。没有锁,并且在所有线程都完成之前,套接字不会关闭。 – 2009-10-01 17:46:54
套接字是一个5元组{local-addr,local-port,remote-addr,remote-port,proto},所以如果你能够使用这些属性而不是fd来处理事件/处理程序路由,你可以避免fd冲突。
另一种选择是序列化所有的close()/接受()操作(重点是什么?),使他们不能混用
我仍然需要互斥体来保护这些结构,这会使系统更加缓慢,这是我试图避免锁定的边缘情况。 – 2009-10-01 15:18:36
保持挂起操作的计数(读/写,等等),每个插座以及套接字上是否有未决的关闭请求。在您要求关闭之前,请先检查是否有任何挂起的操作。如果有,请调用关机代替,然后只在挂起操作计数达到0时调用close。
好问题!我甚至没有意识到可能会出现这样的问题。
我能想到的唯一答案是你没有使用close()来指示套接字被终止。一种解决方案是使用shutdown()来终止连接。然后可以通过引用计数来安全地关闭()插槽。
'close'函数递减底层操作系统中的套接字引用计数,'shutdown'强制关闭并向对等方发送EOF/FIN。看到这个SO帖子的更多细节:http://stackoverflow.com/questions/409783/socket-shutdown-vs-socket-close/598759#598759 – 2009-10-01 17:50:41
正如您发布的链接中提到的,shutdown()不会关闭套接字,只是终止沟通。 Shutdown()会导致任何未决(或未来)的I/O操作失败,但不会释放FD,因此不会发生所描述的问题。在操作失败的情况下,执行该操作的线程将递减引用计数(当线程接收到套接字时,此引用计数已增加),如果该值为零则关闭套接字。显然这个refcount是在程序中实现的,而不是操作系统的引用。 – TrayMan 2009-10-02 04:45:01
你甚至不需要担心引用计数,如果读操作失败就关闭套接字。 – atomice 2009-10-02 15:40:25
我仍然会小心使用dup2()到一个众所周知的fd值。请记住,dup2()将在复制之前在目标上执行关闭;如果你开始打开1000个文件,这可能会与一些不相关I/O的无关线程发生冲突。
如果我是你,给你坚持在制约,我会用DUP()互斥内(不()DUP2)。 (如果你关心它,也许是per-fd mutexes)。
东西是accept&dup2,所有东西都会在同一个线程上执行。所以我可以从MAX_FD跳到10左右,然后重新开始,当MAX_FD刚刚关闭时,dup2()将fd设置为MAX_FD的可能性,因为我们再次开始并不真正被考虑。 – 2009-10-02 06:38:05
但是,你能证明你没有在做无关的文件吗?或者也许某个图书馆代表你做了什么?你能证明自然发生的FD的数量最终不会达到1000吗?也许你可以保证这些事情,但这样的事情会让我对你的方法感到紧张。 – asveikau 2009-10-05 18:46:22
为什么插入一个线程的线程被另一个线程关闭? – 2009-10-01 14:51:29
这就是异步系统的性质,一个操作读取,另一个写入,另一个可能关闭,并且它们全部可以在不同的线程中执行。 – 2009-10-01 14:53:12
重新思考你的方法。通常有一个接受连接的线程,并产生线程来处理它们。那些线程然后负责关闭连接,并且其他线程无法访问该连接。 – 2009-10-01 14:58:57