2015-04-28 109 views
1

我在Win32设备中有一个C++程序。代码具有函数X,该函数应该阻止对X的其他调用。这很简单,我可以使用一个互斥体来实现这一点。锁定多个线程

但是,函数X会创建并启动一个线程Y,该线程将在X完成后监视事物。我需要确保X不能再次运行,直到Y确信一切正常完成。

据我所知,互斥锁只能在同一个线程上获取和释放。我想要做的是将互斥锁的'锁定'从X移交给Y.

如果根据实际发生的情况更容易地描述这一点,那么X在那里打印一些东西,Y是否要检查打印作业是否完成而纸张用完?一旦Y确信工作已经完成并且纸张没有用完,那么它可以让X打印其他东西。我们要X到尽快完成,以便该设备可以与其他的工作吧(这通常不涉及印刷,因此不应承担了,而在打印机完成打印。)

所以...有没有一个标准的交叉线程锁定模式,将做我想做的事情?

我不能使用boost或任何其他第三方库,只能使用Windows内置操作。

+0

也许一个计时器而不是一个线程? –

+0

线程Y将一直运行,直到打印作业完成,并且可以包括通知用户纸张已用完并等待新纸张可用,即可能需要很长时间并且不足以让计时器帮助。 – ColinM

+1

线程X和Y的[同步障碍](https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms686360.aspx#synchronization_barrier_functions)可用于实现此要求。 – IInspectable

回答

2

够简单关注场景。你所需要做的就是用auto-reset event替换互斥量,最初发信号。

的自动重置事件可以以同样的方式被用作一个互斥体(受到一些限制性条款,见下文),但可以通过任何线程发布:

  • 事件开始时发出信号(“无主“)。
  • 要输入函数X,请等待事件。只有一个线程将被允许进入,并且该事件将被自动清除。
  • 函数X启动线程Y,然后退出而没有表示事件。
  • 此时没有线程可以输入函数X,甚至没有进行上一次调用的线程。
  • 当线程Y完成其工作时,它表示该事件。这将允许只有一个线程进入功能X.

有互斥对象和事件对象之间有一些差别,你应该知道的:

  • 与互斥,自动复位事件不允许由同一个线程递归输入。因此,如果函数X自行调用,则需要稍微重新排列代码,以便获取锁定发生在递归之外。

  • 与互斥量不同,如果“拥有”事件的线程意外退出,API不会生成错误。因此,如果Y在没有通知事件的情况下退出,应用程序将陷入僵局。如果这是一个问题,您需要自己监控线程Y的状态。 (当然,同样的道理也适用于线程调用X,如果它推出Y.之前退出)

0

我会扭转线程的顺序:

  • 线程y将会互斥
  • 线程开始出现Y线X做印刷
    • 线程X做它打印和返回
    • 线Y等待其状态并监视打印
  • 线程Y释放互斥锁

这种方式可以让你在同一个线程中锁定和释放互斥锁。此外,您获得的关注一个更好的分离:

  • X只与印刷的交易,甚至不知道的Y
  • Y被同步,并正确打印结束
+0

我喜欢这个想法,虽然它是一个双线程解决方案,而不是创建单个线程的函数。所以在这里启动线程Y的代码将不得不等待,直到X完成,然后我们仍然必须确保在我们等待的时候第二个Y不能启动。 但我会更多地考虑它,因为我喜欢关注的分离。 – ColinM

+0

@ColinM:如果你认为你只需要一个新线程,Y可以是一个在调用线程中运行的函数。我的解决方案只是反转显示器调用打印机,而不是相反。 –

0

我标志着哈利·约翰斯顿的答案接受,因为它听起来像它会做的工作精,似乎是一个很好的通用解我甚至可以使用它。

我现在所做的是用两个临界区对象替换单个互斥体,我们称它们为CSx和CSy。进入X取决于输入CSx。一旦完成,X也进入CSy。然后立即离开CSy,这是因为当线程Y启动时,它将在其生命期内进入CSy。 X进入CSy(并立即离开)的唯一原因是因为这就是它知道线程Y不是从以前的调用运行到X.

这与上面的Erik的注释类似,但不是跟踪单个线程处理它允许多个X和Y排队。

这里的风险是线程Y在函数X离开CSx之前可能不会进入CSy,因此有一个范围让另一个X首先进入,尽管设备的环境和它在做什么意味着它不会实际上发生。

尽管如此,Harry的解决方案还是具有单一锁定对象的优点,以及它带来的简单和优雅。

+0

接受一个答案没有upvoting它看起来是错误的。 – IInspectable