我正在使用管道将遗留应用程序(使用COBOL编写)与我们的.NET新应用程序连接起来。
这个想法很简单:遗留程序(我的ERP菜单)在流上写入一些参数,.NET应用程序通过Console.In
流读取它,并启动一个新线程打开请求的屏幕。以下是.NET方面代码片段,说明了这个想法如何工作:
<STAThread(), LoaderOptimization(LoaderOptimization.MultiDomain)>
Shared Sub Main()
If Environment.GetCommandLineArgs(1) = "PIPE"
While True
Dim pipeParam as String
Try
pipeParam = Console.In.ReadLine()
Catch e as Exception
Exit Sub
End Try
' Deal with parameters here
If pipeParam = "END"
Dim newThread as New Threading.Thread(Sub()
' Create a new AppDomain and Loads the menu option, generally a Winforms form.
End Sub)
newThread.Start()
End If
End While
End If
End Sub
一切都很顺利和简单...... 直到今天。我在客户环境(Windows Server 2003)部署了此解决方案,发现除非调用的进程(COBOL)被终止(即强制关闭
Console.In
),否则不会执行任何请求的线程。从那时起,所有请求的winforms将开始显示并按预期运行。通过日志挖掘这种奇怪的行为,我发现线程正常执行,直到执行
IDictionary.ContainsKey()
语句(或其他需要本机代码执行的方法)的某个点。此时,线程会冻结/休眠。如果我将线程创建限制为三个,那么每个创建的线程都会挂起,直到第三个线程,即当不再执行
Console.In.ReadLine
时。我应该尝试什么?有什么建议吗?
一些更多信息: 到目前为止,我找到的最接近的方向是Hans Passant在这个问题中的回答:Interface freezes in multi-threaded c# application(.NET SystemEvents出现在我的调试器线程列表中,但我无法使用提出的解决方案解决我的问题)。 更新消息 我通过等待子线程完成加载
Form
来解决此问题。这个“准备就绪”的信号通过AppDomain.SetData()
和AppDomain.GetData()
传递。不知何故,在创建表单后,当主线程继续执行Console.ReadLine
时,子线程不再冻结。虽然问题已经解决,但我对此感到好奇。我正在尝试在“尽可能简单”的测试用例中重现这个问题。
一些更多细节
- 入口点.exe编译为32位。所有其他库都是'AnyCpu'。该问题在32位(我的客户端)和64位(我的开发)机器上运行时发生(均为Windows Server 2003)。
- 更新了上面片段中的
Sub Main()
属性。 - 尝试将
Console.ReadLine
放入工作线程。未解决(请参见下面的图像)。 - COBOL应用程序不会冻结,因为它在单独的OS进程中执行。管道是我的IPC方法。在这种情况下,COBOL应用程序仅写入参数,并且不等待响应。
- 堆栈跟踪在下面的图像中(线程
PRX001235
在连接到数据库之前和实际加载表单之前反序列化xml配置文件 - 在这种情况下,似乎仍处于托管代码中 - 有时PRX001235
线程将在尝试连接到数据库时在本机代码中冻结):
While ... ReadLine
循环,并使用 IPC 来检索参数等?在这种情况下,看看是什么导致了程序挂起会很有趣。 - Mark HurdConsole.Readline
上挂起,不管是哪个线程执行该命令(主线程或子线程)。我已经进行了这个测试。实际上,调用Console.ReadLine
的线程在没有输入可用时挂起是可以的,但是所有其他线程都会在某些PInvoke调用上挂起-因为它们也在等待输入。 - J.HudlerReadLine
在Win32API中阻塞,以一种使得所有托管线程都被卡住的方式,而不仅仅是应该被阻塞的线程。 - Mark Hurd