4

我们的(Windows 原生 C++)应用程序由线程对象和管理器组成。它写得非常好,其设计可以看到 Manager 对象控制其 minions 的生命周期。各种对象调度和接收事件;有些事件来自 Windows,有些是自产的。

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

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

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

谢谢。

编辑:

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

4

3 回答 3

3

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

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

至于如何最好地做到这一点......最好的方法(如果可能的话)是尽可能地简化你的程序,如果你可以帮助它,避免一次持有多个锁。

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

于 2011-06-27T23:55:17.447 回答
1

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

于 2011-06-27T07:13:46.747 回答
1

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

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

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

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

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

于 2011-06-27T23:28:37.187 回答