2011-06-26 99 views
4

我们的(Windows本地C++)应用程序由线程对象和管理器组成。它写得非常好,设计中可以看到管理器对象控制着他们的爪牙的生命周期。各种物体发送和接收事件;有些事件来自Windows,有些是自制的。受控应用程序关闭策略

一般情况下,我们有,所以我们使用使用Win32临界区,信号灯等的手卷同步技术是非常知晓线程的互操作性。但是,偶尔我们会因为事件处理程序重入等原因而在关闭期间遭受线程死锁。

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

,我宁愿没有规定重写整个应用程序使用微软的并行模式库或类似的策略。 ;-)

感谢。

编辑:

我想我要求的方法在复杂的应用程序中许多线程和事件被解雇所有的时间控制对象的生命周期。 Giovanni的建议很明显(我们自己动手滚动),但我相信必须有各种现成的策略或框架,才能以正确的顺序干净地关闭活动对象。例如,如果您想将您的C++应用程序基于IoC范例,则可以使用PocoCapsule而不是尝试开发自己的容器。在应用程序中是否有类似的控制对象生命周期?

+0

为什么事件处理程序(已使用)/(尤其是问题)在关机时(而不是在其他时间)? – Mankarse

+1

我只是想写一个答案,但我意识到这个问题是无法解析的,因为它如果你遇到了死锁,那么这不是一个设计问题,而是一个实现问题(当然你现在的设计可能会使一个正确的实现变得不可能)任何修复死锁的设计都是一个改进。 – Mankarse

+0

@mankarse因为我们的关闭策略在某些地方不够强大,以防止在事件被调度和处理的过程中出现死锁,当然这些都是简单的错误,并且当发现时,这些错误是固定的。 – dripfeed

回答

1

一个可能的一般策略是发送“我在关停”事件,每一位经理,这将导致经理人做的三两件事之一(具体上运行的事件处理程序是多长时间,多少您希望启动关机的用户和应用程序实际退出之间的延迟)。

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

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

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

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

1

作为一般的方法,使用原子布尔值,表明“我是关停”,那么每一个线程检查获取的每个锁,每次处理事件之前这个布尔等不能,除非你给我们提供一个更详细的解答一个更详细的问题。

3

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

答案就是,一如既往:确保任何时候你的线程必须一次获得多个锁,它们都以相同的顺序获得锁,并确保所有线程释放它们锁定在有限的时间内。此规则在关机时与其他时间一样适用。没有什么是不够的;没有更多是必要的。 (请参阅here进行相关讨论)

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

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

+0

+1锁定策略链接。 – dripfeed