我正在使用管道将旧应用程序(用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
被强制关闭)。从那时起,所有请求的winform将开始显示并按预期方式运行。用日志挖掘这种奇怪的行为,我发现线程一直在正常执行,直到执行了
IDictionary.ContainsKey()
语句(或其他需要执行 native 代码的方法)为止。此时,线程处于冻结/休眠状态。如果我将线程创建限制为三个,那么碰到的是,每个创建的线程都将挂起,直到第三个线程挂起,即不再执行
Console.In.ReadLine
。我应该怎么做?有什么建议吗?
更多信息:
到目前为止,我找到的最接近的方向是汉斯·帕森特(Hans Passant)在这个问题上的答案:
Interface freezes in multi-threaded c# application(.NET SystemEvents恰巧出现在我的调试器线程列表中,但使用建议的解决方案无法解决我的问题)。
更新新闻
我可以通过等待子线程完成
Form
的加载来解决此问题。该“Is Ready”信号通过AppDomain.SetData()
和AppDomain.GetData()
传递。以某种方式,在表单创建之后,当主线程进入Console.ReadLine
时,子线程不再冻结。尽管问题已解决,但我对此很感兴趣。我试图在“尽可能简单”的测试用例中重现这一点。一些更多详细信息
Sub Main()
属性。 Console.ReadLine
放入工作线程中。未解决(请参见下图)。 PRX001235
在连接到数据库之前和有效加载表单之前对XML配置文件进行反序列化-在这种情况下,似乎仍处于托管代码中-有时PRX001235
线程将冻结在其中尝试连接到数据库时的 native 代码):最佳答案
首先,您正在做非常不寻常的事情,因此不寻常的结果并不意外。其次,您要执行的操作严格是Windows SDK文档中的verboten。这表明创建单线程单元的线程决不允许进行阻塞调用。
显然,您的工作线程被锁定在操作系统肠道内部某处的锁上,该锁由程序的主线程获取。看到那些被阻塞线程之一的调用堆栈来识别可能的锁定会很有帮助。这需要启用非托管代码调试,以便您可以查看非托管堆栈框架并启用Microsoft Symbol Server,以便获取Windows代码的调试符号,并可以从堆栈跟踪中了解信息。
没有人看,我不得不推测:
鉴于解决方案非常简单,因此不确定是否值得追究此问题的原因。只是不要在主线程上调用Console.ReadLine()。而是在辅助线程上调用它。当COBOL程序无响应时,这也可以防止UI冻结。但是请注意,如果您收到的任何内容也会更新您的UI,则现在必须使用Control.Begin/Invoke()进行编码。
关于.net - Console.In.ReadLine(重定向的StdIn)卡住所有其他线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13437171/