跟踪并正确结束 C# 中的本机和托管线程 - C++/CLI - C++退出之前的 Windows 窗体应用程序
这是以下内容的后续内容:
在 Visual Studio 2008 中调试多线程 C# - C++/CLI - C++ 解决方案:这些线程是什么?
请原谅格式,我只是在这里重复了应用程序的一些描述:
我继承了一个项目由三层代码组成。最底层是与硬件交互的本机 C++。这是成熟、稳定且经过充分测试的。中级代码是 C++/CLI,它与包含 UI 元素和一些附加功能的顶级 C# 代码进行交互。此 C# 代码不完整,并且开发仓促:它经常崩溃并且不适合用途。我的任务是调试它并完成它。
我从我提出的最后一个问题中收到了一些非常有用的信息 - 但现在有更多问题!我目前的问题是,当我调用 Application.Exit() 来关闭 UI 并退出应用程序时,会引发异常:
System.InvalidOperationException: Collection was modified; enumeration operation may not execute
我明白这是因为我需要确保在调用之前所有线程都已结束Application.Exit()(或Application.ExitThread())。我在进一步调查时尝试使用 MainForm.Close() 作为快速修复,但它并不能缓解问题。
我不想只调用 Thread.CurrentThread.Abort(),主要是因为某些线程源自代码的 C++ 部分,通过 Boost::Thread,并且我不确定我可能会在不良状态(很多代码由与硬件交互的对象组成,例如串行端口 - 它不是通过 RAII 实现的,所以我对暴力破解非常谨慎)。
我希望能够做的是识别哪些线程正在做什么,并在退出应用程序之前优雅地结束它们。然而,在 VS 2008 中,堆栈跟踪(激活“显示外部代码”)只会显示,
[Native to managed transition]
[Managed to native transition]
因此我仍然难以跟踪各个本机线程,从而找出结束它们的最佳方法。
我尝试使用 Allinea DDTLite,这看起来很棒 - 但我的 VS 安装遇到了一些问题,我不得不禁用插件,所以这不是一个解决方案。
总结一下:确保所有线程(托管线程和本机线程)正确完成的最有效方法是什么,以便 UI 和 整个应用程序可以干净退出吗?
This is a follow-on from:
Debugging a Multithreaded C# - C++/CLI - C++ Solution in Visual Studio 2008: What are these threads?
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. 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. This C# code is incomplete and was rushed in development: it crashes frequently and is not fit for purpose. 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:
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()). I've tried using MainForm.Close() as quick fix while I investigate further but it doesn't alleviate the problem.
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).
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
[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.
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您无法完成的操作。有多种方法可以枚举进程中的线程,例如托管 Process.Threads 属性或本机 Thread32First/Next,但您无法获得足够的有关线程的信息来了解它们的用途。最肯定的是不要彻底关闭它们。 .NET 框架将线程用于其自身目的,例如调试器线程和终结器线程以及少量线程池线程,这使情况变得更加复杂。
你可以使用TerminateThread粗暴地终止这些线程,尽管终止终结器线程会立即使程序崩溃,但这与使用Environment.Exit()粗暴地终止进程没有什么不同。需要注意的是,没有任何东西可以很好地清理干净。不过,Windows 会清理大部分弹片。
这通常不应该成为问题。您知道您启动了哪些线程,还应该有一种机制来要求它们关闭。这通常是通过发出事件信号来完成的,该事件在线程的主循环中进行测试。等待线程句柄确认线程确实退出。之后您可以关闭窗户。
但这可能是缺少的管道,您必须添加它。如果当前的本机 C++ 代码没有处理线程关闭的机制,那么您就会遇到一个相当大的问题。我猜维护这个本机 C++ 代码才是真正的问题。您可能需要租一把枪才能完成此任务。
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. 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.
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(). With the caveat that nothing is cleaned-up nicely. Windows will clean up most of the shrapnel though.
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. I'll guess that maintaining this native C++ code is the real problem. You may have to hire a gun to get this done.