我正在开发一个具有一个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()还是其他原因造成的。
答案 0 :(得分:4)
WSAStartup函数通常会导致加载特定于协议的帮助程序DLL。因此,不应从应用程序DLL中的DllMain函数调用WSAStartup函数。这可能会导致死锁。在DLL加载器关键部分中调用Dllmain,这是导致此死锁的主要原因 更多细节 : http://msdn.microsoft.com/en-us/library/windows/desktop/ms742213%28v=vs.85%29.aspx
答案 1 :(得分:2)
您根本不必多次致电WSAStartup()
。一个程序就好了。
答案 2 :(得分:1)
我认为卢克是对的。您不能在DllMain()或全局/静态变量的初始值设定项中调用WSAStartup()。更改您的代码,以便不会发生。
答案 3 :(得分:0)
WSAStartup 实际上并不会导致任何类型的 LoadLibrary ,因此我不认为这是loader lock
案例。
相反,显而易见的是,Windows API被困在你的案例中(术语trap
在这里更好,因为hook
在Windows中具有其他含义。)
因此,我认为问题不在于并发使用 WSAStartup ,而在于第三方陷阱的副作用优于您的进程中的原始Windows API函数。我认为,您需要清除环境中的任何外部影响(来自您身边的api陷阱或来自防病毒软件,无论如何)。
顺便说一下,确保你的每个线程都为WSAStartup提供了自己独立的WSADATA输出参数副本