简体   繁体   English

退出前跟踪-并正确结束-C#中的本机线程和托管线程-C ++ / CLI-C ++ Windows窗体应用程序

[英]Tracking - and correctly ending - native and managed threads in a C# - C++/CLI - C++ Windows forms application prior to exit

This is a follow-on from: 这是来自以下方面的后续文章:

Debugging a Multithreaded C# - C++/CLI - C++ Solution in Visual Studio 2008: What are these threads? 在Visual Studio 2008中调试多线程C#-C ++ / CLI-C ++解决方案:这些线程是什么?

Please excuse the format, I've just repeated some of the description of the application here: 请原谅格式,我在这里重复了对应用程序的一些描述:

I've inherited a project consisting of three levels of code. 我继承了一个包含三个级别的代码的项目。 The lowest layer is native C++ that interacts with hardware. 最底层是与硬件交互的本机C ++。 This is mature, stable and well-tested. 这是成熟,稳定且经过测试的。 The intermediate level code is C++/CLI, which interacts with top-level C# code that contains the UI elements and some additional functionality. 中级代码是C ++ / CLI,它与包含UI元素和一些其他功能的顶级C#代码进行交互。 This C# code is incomplete and was rushed in development: it crashes frequently and is not fit for purpose. 该C#代码不完整,已被迫着急进行开发:它经常崩溃,不符合特定目的。 My task is debug it and complete it. 我的任务是调试并完成它。

I received some very helpful info from the last question I asked - but now there's more issues! 我从上一个问题中得到了一些非常有用的信息-但是现在还有更多问题! My problem at the moment is that when I invoke Application.Exit() to shut down the UI and quit the application, an exception is thrown: 目前我的问题是,当我调用Application.Exit()以关闭UI并退出应用程序时,会引发异常:

System.InvalidOperationException: Collection was modified; enumeration operation may not execute

I understand that this is because I need to ensure that all of my threads are ended before I call Application.Exit() (or Application.ExitThread()). 我了解这是因为在调用Application.Exit()(或Application.ExitThread())之前,我需要确保所有线程都已结束。 I've tried using MainForm.Close() as quick fix while I investigate further but it doesn't alleviate the problem. 在进行进一步调查时,我尝试使用MainForm.Close()作为快速解决方案,但这并不能缓解问题。

I don't want to just called Thread.CurrentThread.Abort(), mainly because some of the threads originate in the C++ section of the code, via Boost::Thread, and I'm unsure exactly what resources I may leave in an undesirable state (a lot of the code consists of objects for interaction with hardware, such as a serial port - it's not been implemented via RAII so I'm rather cautious of brute forcing things). 我不想只调用Thread.CurrentThread.Abort(),主要是因为某些线程通过Boost :: Thread起源于代码的C ++部分,而我不确定到底可以在其中保留哪些资源。不期望的状态(很多代码由与硬件交互的对象组成,例如串行端口-尚未通过RAII实现,因此我对强制性操作非常谨慎)。

What I'd like to be able to do is identify what threads are doing what, and gracefully end them prior to exiting the application. 我想做的是确定什么线程在做什么,并在退出应用程序之前优雅地结束它们。 However, in VS 2008, the stack trace - with 'Show External Code' activated - only reveals 但是,在VS 2008中,堆栈跟踪-已激活“显示外部代码”-仅显示

[Native to managed transition]
[Managed to native transition]

so I'm still having difficulty tracing the individual native threads and thus working out the best way to end them. 因此,我仍然很难跟踪各个本机线程,从而找到了结束它们的最佳方法。

I tried using Allinea DDTLite, which seemed excellent - but I've had some issues with my VS installation and I had to disable the plug-ins, so it wasn't a solution. 我尝试使用Allinea DDTLite,它看起来很棒-但是我的VS安装遇到了一些问题,我不得不禁用插件,所以这不是解决方案。

To summarise: what is the most effective way to ensure that all threads - both managed and native - are correctly finished so that the UI and then the the entire application can exit cleanly? 总结:确保所有线程(托管线程和本机线程)正确完成的最有效方法是什么,以便UI以及整个应用程序都可以正常退出?

What I'd like to be able to do is identify what threads are doing what 我想做的是确定什么线程在做什么

You cannot make this work. 您无法完成这项工作。 There are ways to enumerate the threads in a process, like the managed Process.Threads property or the native Thread32First/Next but you don't get nearly enough info about the threads to know what they do. 有多种方法可以枚举进程中的线程,例如托管的Process.Threads属性或本机Thread32First / Next,但是您没有获得足够的有关线程的信息来知道它们在做什么。 And most certainly not to shut them down cleanly. 而且最肯定的是不要干净地关闭它们。 Further complicated by the .NET framework using threads for its own purposes, like the debugger thread and the finalizer thread and a smattering of threadpool threads. .NET框架将线程用于其自己的目的,使进一步复杂化,例如调试器线程和终结器线程以及少量线程池线程。

You can kill these threads rudely with TerminateThread, albeit that killing the finalizer thread will crash the program immediately, but that's no different from rudely terminating the process with Environment.Exit(). 您可以使用TerminateThread粗心地杀死这些线程,尽管杀死终结器线程将立即使程序崩溃,但这与通过Environment.Exit()粗暴地终止进程没有什么不同。 With the caveat that nothing is cleaned-up nicely. 需要注意的是,没有任何东西可以很好地清理。 Windows will clean up most of the shrapnel though. Windows会清理大部分弹片。

This should not normally be a problem. 通常这应该不是问题。 You know what threads you started, there should also be a mechanism to ask them to shut down. 您知道启动了哪些线程,还应该有一种机制要求它们关闭。 That's normally done by signaling an event, something that's tested in thread's main loop. 通常通过发信号通知事件来完成,该事件已在线程的主循环中进行了测试。 Waiting on the thread handle confirms that the thread indeed exited. 等待线程句柄确认线程确实退出。 After which you can close the windows. 之后,您可以关闭窗口。

But that's probably plumbing that's missing, you'll have to add it. 但这可能是缺少的管道,您必须添加它。 If the current native C++ code has no mechanism to take care of thread shutdown then you've got a fairly big problem. 如果当前的本机C ++代码没有机制来处理线程关闭,那么您将遇到一个很大的问题。 I'll guess that maintaining this native C++ code is the real problem. 我猜想维护本机C ++代码是真正的问题。 You may have to hire a gun to get this done. 您可能需要租用枪才能完成此任务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM