受控应用程序关闭策略

发布于 2024-11-17 16:56:41 字数 568 浏览 9 评论 0原文

我们的(Windows 原生 C++)应用程序由线程对象和管理器组成。它写得很好,其设计让 Manager 对象控制其 Minion 的生命周期。各种对象发送和接收事件;有些事件来自 Windows,有些是本地事件。

一般来说,我们必须非常了解线程互操作性,因此我们使用 Win32 临界区、信号量等手动同步技术。然而,有时我们会因为事件处理程序重入等原因而在关闭期间遇到线程死锁。

现在我想知道我们是否可以实施一个像样的应用程序关闭策略,以使其更容易开发 - 就像每个对象从中央控制器注册关闭事件并相应地改变其执行行为一样?这是否太天真或脆弱?

我更喜欢不规定重写整个应用程序以使用 Microsoft 的并行模式库或类似库的策略。 ;-)

谢谢。

编辑:

我想我正在寻求一种方法来控制复杂应用程序中的对象生命周期,其中许多线程和事件一直在触发。乔瓦尼的建议是显而易见的(我们自己动手),但我相信必须有各种现成的策略或框架,以便以正确的顺序彻底关闭活动对象。例如,如果您想将 C++ 应用程序基于 IoC 范例,您可以使用 PocoCapsule,而不是尝试开发自己的容器。是否有类似的东西可以控制应用程序中的对象生命周期?

Our (Windows native C++) app is composed of threaded objects and managers. It is pretty well written, with a design that sees Manager objects controlling the lifecycle of their minions. Various objects dispatch and receive events; some events come from Windows, some are home-grown.

In general, we have to be very aware of thread interoperability so we use hand-rolled synchronization techniques using Win32 critical sections, semaphores and the like. However, occasionally we suffer thread deadlock during shut-down due to things like event handler re-entrancy.

Now I wonder if there is a decent app shut-down strategy we could implement to make this easier to develop for - something like every object registering for a shutdown event from a central controller and changing its execution behaviour accordingly? Is this too naive or brittle?

I would prefer strategies that don't stipulate rewriting the entire app to use Microsoft's Parallel Patterns Library or similar. ;-)

Thanks.

EDIT:

I guess I am asking for an approach to controlling object life cycles in a complex app where many threads and events are firing all the time. Giovanni's suggestion is the obvious one (hand-roll our own), but I am convinced there must be various off-the-shelf strategies or frameworks, for cleanly shutting down active objects in the correct order. For example, if you want to base your C++ app on an IoC paradigm you might use PocoCapsule instead of trying to develop your own container. Is there something similar for controlling object lifecycles in an app?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

兔姬 2024-11-24 16:56:41

这似乎是更普遍的问题的一个特例,“如何避免多线程应用程序中的死锁?”

与往常一样,答案是:确保任何时候您的线程必须一次获取多个锁,它们都以相同的顺序获取锁,并确保所有线程在有限的时间内释放它们的锁。时间量。该规则在关机时和其他任何时间一样适用。没有什么比这更好的了;没有更多的必要了。 (请参阅此处了解相关讨论)

至于如何最好地做到这一点......最好的方法(如果可能)是尽可能简化你的程序,并避免在同一时刻持有多个锁如果你能帮忙的话,时间到了。

如果您绝对必须一次持有多个锁,则必须验证您的程序以确保持有多个锁的每个线程都以相同的顺序锁定它们。像 helgrind 或 Intel 线程检查器 这样的程序可以帮助解决此问题,但通常归结为简单地查看代码直到你向自己证明它满足这个约束。此外,如果您能够轻松地重现死锁,您可以检查(使用调试器)每个死锁线程的堆栈跟踪,这将显示死锁线程永远被阻塞的位置,并利用该信息,您可以开始找出代码中锁顺序不一致的地方。是的,这是一个很大的痛苦,但我认为没有任何好的方法可以解决它(除了避免同时持有多个锁)。 :(

This seems like a special case of the more general question, "how do I avoid deadlocks in my multithreaded application?"

And the answer to that is, as always: make sure that any time your threads have to acquire more than one lock at a time, that they all acquire the locks in the same order, and make sure all threads release their locks in a finite amount of time. This rule applies just as much at shutdown as at any other time. Nothing less is good enough; nothing more is necessary. (See here for a relevant discussion)

As for how to best do this... the best way (if possible) is to simplify your program as much as you can, and avoid holding more than one lock at a time if you can possibly help it.

If you absolutely must hold more than one lock at a time, you must verify your program to be sure that every thread that holds multiple locks locks them in the same order. Programs like helgrind or Intel thread checker can help with this, but it often comes down to simply eyeballing the code until you've proved to yourself that it satisfies this constraint. Also, if you are able to reproduce the deadlocks easily, you can examine (using a debugger) the stack trace of each deadlocked thread, which will show where the deadlocked threads are forever-blocked at, and with that information, you can that start to figure out where the lock-ordering inconsistencies are in your code. Yes, it's a major pain, but I don't think there is any good way around it (other than avoiding holding multiple locks at once). :(

以歌曲疗慰 2024-11-24 16:56:41

一种可能的通用策略是向每个管理器发送“我正在关闭”事件,这将导致管理器执行以下三件事之一(取决于事件处理程序的运行时间,以及您希望之间的延迟时间)用户启动关闭,应用程序实际退出)。

1) 停止接受新事件,并运行“我正在关闭”事件之前收到的所有事件的处理程序。为了避免死锁,您可能需要接受对于完成其他事件处理程序至关重要的事件。这些可以通过事件中的标志或事件类型(例如)来表示。如果您有此类事件,那么您还应该考虑重构您的代码,以便这些操作不通过事件处理程序执行(因为相关事件在普通操作中也容易出现死锁。)

2) 停止接受新事件,并丢弃在处理程序当前正在运行的事件之后接收到的所有事件。关于相关事件的类似评论也适用于这种情况。

3) 中断当前正在运行的事件(使用类似于boost::thread::interrupt()的函数),并且不再运行其他事件。这要求您的处理程序代码是异常安全的(如果您关心资源泄漏,它应该已经是安全的),并且以相当规律的间隔进入中断点,但这会导致最小的延迟。

当然,您可以将这三种策略混合在一起,具体取决于每个经理的特定延迟和数据损坏要求。

One possible general strategy would be to send an "I am shutting down" event to every manager, which would cause the managers to do one of three things (depending on how long running your event-handlers are, and how much latency you want between the user initiating shutdown, and the app actually exiting).

1) Stop accepting new events, and run the handlers for all events received before the "I am shutting down" event. To avoid deadlocks you may need to accept events that are critical to the completion of other event handlers. These could be signaled by a flag in the event or the type of the event (for example). If you have such events then you should also consider restructuring your code so that those actions are not performed through event handlers (as dependent events would be prone to deadlocks in ordinary operation too.)

2) Stop accepting new events, and discard all events that were received after the event that the handler is currently running. Similar comments about dependent events apply in this case too.

3) Interrupt the currently running event (with a function similar to boost::thread::interrupt()), and run no further events. This requires your handler code to be exception safe (which it should already be, if you care about resource leaks), and to enter interruption points at fairly regular intervals, but it leads to the minimum latency.

Of course you could mix these three strategies together, depending on the particular latency and data corruption requirements of each of your managers.

南七夏 2024-11-24 16:56:41

作为一般方法,使用原子布尔值来指示“我正在关闭”,然后每个线程在获取每个锁、处理每个事件等之前检查这个布尔值。除非您给我们一个更详细的问题,否则无法给出更详细的答案。

As a general method, use an atomic boolean to indicate "i am shutting down", then every thread checks this boolean before acquiring each lock, handling each event etc. Can't give a more detailed answer unless you give us a more detailed question.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文