锁定多个线程

时间:2015-04-28 15:07:49

标签: c++ windows multithreading winapi

我在Win32设备中有一个C ++程序。代码有函数X,应该阻止对X的其他调用。这很简单,我可以使用互斥量来做到这一点。

然而,函数X创建并启动一个线程Y,它将在X完成后监视事物。我需要确保X不能再次运行,直到Y确信所有内容都已正确完成。

据我了解,只能在同一个线程上获取并释放互斥锁。我想做的是将互斥锁的“锁定”从X移交给Y.

如果根据实际情况更容易想象这一点,X可以打印一些东西,Y可以检查打印作业是否完成而不会耗尽纸张。一旦Y确信作业已经完成并且纸张没有用完,那么它可以让X打印其他内容。我们希望X尽快完成,以便设备可以继续进行其他工作(通常不涉及打印,因此在打印机完成时不应该停止。)

那么......是否有一个标准的跨线程锁定模式可以做我想做的事情?

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

3 个答案:

答案 0 :(得分:2)

这是一个足够简单的场景。您需要做的就是用最初发出信号的auto-reset event替换互斥锁。

自动重置事件的使用方式与互斥锁相同(受某些条款限制,见下文),但可以由任何线程释放:

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

您应该注意的互斥对象和事件对象之间存在一些差异:

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

  • 与互斥锁不同,如果"拥有"的线程,API将不会生成错误。事件意外退出。因此,如果Y在没有发出事件信号的情况下退出,应用程序将会死锁。如果这是一个问题,您需要自己监视线程Y的状态。 (当然,相同的推理适用于调用X的线程,如果它在启动Y之前退出。)

答案 1 :(得分:0)

我会颠倒线程的顺序:

  • 线程Y使用互斥锁
  • 线程Y启动线程X进行打印
    • 线程X打印并返回
    • 线程Y等待其条件并监视打印
  • 线程Y释放互斥锁

这种方式允许您在同一个线程中锁定和释放互斥锁。此外,您可以更好地分离问题:

  • X仅处理打印,甚至不知道Y
  • Y关注同步和正确的打印结束

答案 2 :(得分:0)

我将Harry Johnston的答案标记为已被接受,因为听起来它可以很好地完成工作,并且似乎是一个很好的通用解决方案。我甚至可以使用它。

我现在所做的是用两个关键部分对象替换单个互斥锁,让我们称之为CSx和CSy。进入X取决于进入CSx。一旦完成,X也进入CSy。它然后立即离开CSy,这是因为当线程Y被启动时,它将在其生命期间进入CSy。 X进入CSy(并立即离开)的唯一原因是因为它知道线程Y没有从之前的X调用运行。

这类似于上面的Erik评论,但它不是跟踪单个线程句柄,而是允许多个X和Y排队。

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

即使如此,Harry的解决方案还有一个锁定物体的优点,以及它带来的简洁和优雅。