从多个线程调用 WSAStartup() 会导致死锁吗?
我正在开发一个应用程序,它有一个 TCP 服务器和多个 UDP 服务器/侦听器。每个服务器都是一个单独的线程,与已建立的 TCP 连接的工作线程相同。我在每个线程中调用 WSAStartup() 。
有时,调用 WSAStartup() 会挂起(对我来说这看起来像是死锁)。这是堆栈跟踪:
ntdll.dll!_KiFastSystemCallRet@0()
ntdll.dll!_ZwWaitForSingleObject@12() + 0xc bytes
ntdll.dll!_RtlpWaitForCriticalSection@4() + 0x8c bytes
ntdll.dll!_RtlEnterCriticalSection@4() + 0x46 bytes
ntdll.dll!_LdrpGetProcedureAddress@20() + 0x17d bytes
ntdll.dll!_LdrGetProcedureAddress@16() + 0x18 bytes
kernel32.dll!_GetProcAddress@8() + 0x3e bytes
vld.dll!03203723()
[Frames below may be incorrect and/or missing, no symbols loaded for vld.dll]
ws2_32.dll!CheckForHookersOrChainers() + 0x22 bytes
ws2_32.dll!_WSAStartup@8() + 0xa7 bytes
此死锁发生在初始化混乱期间。我看到 TCP 服务器已启动,并建立了一个 TCP 连接,而仅启动了一台 UDP 服务器。堆栈跟踪来自应启动其余 UDP 服务器的函数。我的猜测是,当我尝试初始化 UDP 服务器并调用 WSACStartup() 时,另一个步骤是处理另一个套接字操作,例如一个新的 TCP 连接,并且它还调用 WSAStartup() ?
我的问题是从多个线程调用 WSAStartup() 是否会导致此死锁? 我还检查了死锁之前调用的 WSACleanup() ,但事实并非如此。执行永远不会到达任何 WSACleanup()。
我知道只调用一次 WSAStartup 就足够了,但多次调用 WSAStartup() 应该不是问题 (MSDN]1): “如果应用程序需要多次获取 WSADATA 结构信息,则可以多次调用 WSAStartup。” 因此,我想确定这个死锁是由 WSAStartup() 还是其他原因引起的。
I'm developing an app that has one TCP server and several UDP servers/listeners. Each server is a separate thread, same as the worker threads for established TCP connections. I'm calling WSAStartup() in each of the threads.
Sometimes, calling WSAStartup() hangs (it looks like a deadlock to me). Here is the stack trace:
ntdll.dll!_KiFastSystemCallRet@0()
ntdll.dll!_ZwWaitForSingleObject@12() + 0xc bytes
ntdll.dll!_RtlpWaitForCriticalSection@4() + 0x8c bytes
ntdll.dll!_RtlEnterCriticalSection@4() + 0x46 bytes
ntdll.dll!_LdrpGetProcedureAddress@20() + 0x17d bytes
ntdll.dll!_LdrGetProcedureAddress@16() + 0x18 bytes
kernel32.dll!_GetProcAddress@8() + 0x3e bytes
vld.dll!03203723()
[Frames below may be incorrect and/or missing, no symbols loaded for vld.dll]
ws2_32.dll!CheckForHookersOrChainers() + 0x22 bytes
ws2_32.dll!_WSAStartup@8() + 0xa7 bytes
This deadlock happens during the initialization faze. I see that the TCP server is started and that one TCP connection is established, while only one of UDP servers is started. The stack trace is from the function that should initiate the rest of UDP servers. My guess is that while I'm trying to init UDP sever and calling WSACStartup(), another tread is handling another socket operation, for example a new TCP connection and it's also calling WSAStartup()?
My question is whether calling WSAStartup() from several threads can cause this deadlock?
Also I checked is the WSACleanup() called before the deadlock, and it isn't. The execution never reaches any of WSACleanup().
I'm aware that only one call to WSAStartup should be enough, yet calling WSAStartup() several times should not be a problem (MSDN]1):
"An application can call WSAStartup more than once if it needs to obtain the WSADATA structure information more than once."
Hence, I would like to establish whether this deadlock is caused by WSAStartup() or something else.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
WSAStartup 函数通常会导致加载特定于协议的帮助程序 DLL。因此,不应从应用程序 DLL 中的 DllMain 函数调用 WSAStartup 函数。这可能会导致死锁。 Dllmain 在 DLL 加载程序临界区中被调用,这是造成死锁的主要原因。
欲了解更多详情:
http://msdn.microsoft .com/en-us/library/windows/desktop/ms742213%28v=vs.85%29.aspx
The WSAStartup function typically leads to protocol-specific helper DLLs being loaded. As a result, the WSAStartup function should not be called from the DllMain function in an application DLL. This can potentially cause deadlocks. Dllmain is called in DLL loader critical section which is primary reason of this deadlock.
For more details :
http://msdn.microsoft.com/en-us/library/windows/desktop/ms742213%28v=vs.85%29.aspx
您根本不必多次调用
WSAStartup()
。每个程序一次就可以了。You don't have to call
WSAStartup()
multiple times at all. Once per program is fine.我认为卢克是对的。您不能在 DllMain() 或全局/静态变量的初始值设定项中调用 WSAStartup()。更改您的代码,以免发生这种情况。
I think that Luke is right. You cannot call WSAStartup() in DllMain() or in initializers of global/static variables. Change your code so that it does not happen.
WSAStartup 实际上不会导致任何类型的LoadLibrary,所以我不认为这是一个
加载器锁
情况。相反,很明显 Windows API 被困在你的情况中(这里术语
trap
更好,因为hook
在 Windows 中有其他含义)。因此,我认为问题不在于并发使用WSAStartup,而在于您的进程中第三方陷阱对原始 Windows API 函数的副作用。我认为,您需要清理您的环境,使其免受任何外部影响(您这边的 API 陷阱或防病毒软件等)。
顺便说一句,请确保您的每个线程都为 WSAStartup 提供其自己的 WSADATA 输出参数的单独副本
WSAStartup doesn't actually lead to LoadLibrary of any kind, so I don't feel like it is a
loader lock
case.Instead, it is obvious that windows API is being trapped in your case (term
trap
is better here, becausehook
has other meaning in Windows).Thus, I believe that the problem is not in concurrent use of WSAStartup, but in side effects of third party traps over original Windows API functions in your process. I think, you need to clean up your environment from any external influence (api traps from your side or from anti-virus software, whatever).
By the way, make sure that each thread of yours provides WSAStartup with its own separate copy of WSADATA output parameter