我在分层基础架构上的 Linux 环境中工作,其中每一层都是一个独立的进程,它使用某种套接字连接与它上面或下面的层进行通信。它可以是 UNIX、TCP、UDP,协议无关紧要。为了使这个方案起作用,任何不是最顶层或最底层的进程都必须同时具有服务器和客户端套接字。我们正在使用一个简单的库,它为每个连接(即发送和接收)的运行时创建一个线程,该线程由互斥保护队列提供。这个库中的代码使用 select() 调用和 fd 集来监视每个套接字,并且当连接在它们自己的进程中被隔离时可以完美地工作。但是,当我们尝试在单个进程中使用两个或多个线程套接字处理程序时,我们面临着我认为 select() 调用的死锁,
我们正在使用的测试用例(只是一个简单的 .cpp 模块,不是正式的单元测试)将不断发送但从不接收。它应该做的是回显任何一个连接处理程序正在相互发送的消息。重要的是要知道处理程序不是通过套接字进行通信,而是能够在进程的内存中传递消息(通过在线程 1 中运行的“路由”算法实现)。线程 1 也不断地发送消息,由任一服务器通过互斥锁保护队列发送出去,并且它不是这些互斥锁的死锁。
这是我可以用调试器看到的
(gdb) info threads
3 Thread 0xb7525b70 (LWP 5001) 0xb7fe2424 in __kernel_vsyscall ()
2 Thread 0xb7d26b70 (LWP 5000) 0xb7fe2424 in __kernel_vsyscall ()
* 1 Thread 0xb7d276d0 (LWP 4999) 0xb7f64370 in std::string::length() const () from /usr/lib/libstdc++.so.6
这不是两个线程死锁在同一个套接字上的问题,因为它们没有共享一个套接字或试图通过一个套接字进行通信。在我看来,竞争select()
调用导致进程一次又一次地挂起,因此连接处理程序都无法将传出消息写入套接字。我尝试将两个连接的超时设置为 1 微秒,但没有效果。
ascii地图:
thread 2 thread 1 thread 3
[[server socket a] <-> [server a]] <-> [intermediary] <-> [[server b] <-> [server socket b]]
如果更多细节有用的话,我可以从我们的库中发布代码(我们正计划发布 FOSS 版本)。如果有人可以肯定地将此识别为死锁,他们是否可以更进一步并推荐解决方法?
谢谢!