5

我正在开发一个具有一个 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 

这种死锁发生在初始化 faze 期间。我看到 TCP 服务器已启动并建立了一个 TCP 连接,而仅启动了一个 UDP 服务器。堆栈跟踪来自应该启动其余 UDP 服务器的函数。我的猜测是,当我尝试初始化 UDP 服务器并调用 WSACStartup() 时,另一个线程正在处理另一个套接字操作,例如一个新的 TCP 连接,它也在调用 WSAStartup()?

我的问题是从多个线程调用 WSAStartup() 是否会导致这种死锁?我还检查了死锁之前调用的 WSACleanup() ,但事实并非如此。执行永远不会到达任何 WSACleanup()。

我知道只调用一次 WSAStartup 就足够了,但多次调用 WSAStartup() 应该不是问题(MSDN] 1):“如果需要获取 WSADATA 结构信息,应用程序可以多次调用 WSAStartup不止一次。” 因此,我想确定这个死锁是由 WSAStartup() 还是其他原因引起的。

4

4 回答 4

4

WSAStartup 函数通常会导致加载特定于协议的帮助程序 DLL。因此,不应从应用程序 DLL 中的 DllMain 函数调用 WSAStartup 函数。这可能会导致死锁。Dllmain 在 DLL 加载程序临界区被调用,这是造成这种死锁的主要原因。
更多详情:http: //msdn.microsoft.com/en-us/library/windows/desktop/ms742213%28v=vs.85%29.aspx

于 2013-10-03T22:44:28.630 回答
3

You don't have to call WSAStartup() multiple times at all. Once per program is fine.

于 2010-08-05T18:41:40.577 回答
1

我认为卢克是对的。您不能在 DllMain() 或全局/静态变量的初始化程序中调用 WSAStartup()。更改您的代码,使其不会发生。

于 2010-08-05T19:10:18.097 回答
0

WSAStartup实际上不会导致任何类型的LoadLibrary,所以我不觉得这是一个loader lock案例。

相反,很明显 Windows API 被困在你的情况下(trap这里的术语更好,因为hook在 Windows 中有其他含义)。

因此,我认为问题不在于同时使用WSAStartup,而在于第三方陷阱在您的进程中对原始 Windows API 函数的副作用。我认为,您需要清理环境免受任何外部影响(来自您身边的 api 陷阱或防病毒软件等)。

顺便说一句,请确保您的每个线程都为 WSAStartup 提供其自己的 WSADATA 输出参数的单独副本

于 2010-08-05T21:19:26.170 回答