【问题标题】:Windows synchronization on multiple mutexes多个互斥锁上的 Windows 同步
【发布时间】:2012-06-09 17:42:11
【问题描述】:

我不清楚,有人可以帮我确认一下吗?

我有以下同步问题。我有以下对象:

A. Process 1, thread 1: Read & write access to the resource.
B. Process 1, thread 2: Read access to the resource.
C. Process 2, thread 3: Read access to the resource.

这是访问条件:

  1. 必须在 B 或 C 开启时阻止 A。
  2. 只有在 A 开启时才能阻止 B。
  3. 只有在 A 开启时才能阻止 C。

所以我想为此使用 2 个命名互斥锁:

  • hMutex2 = 用于满足上述条件 2。
  • hMutex3 = 用于满足上述条件 3。
  • hStopEvent = 一个停止事件(如果应用正在关闭,则需要停止线程)。

所以对于 A:

HANDLE hHandles[3] = {hMutex2, hMutex3, hStopEvent};
DWORD dwRes = WaitForMultipleObjects(3, hHandles, FALSE, INFINITE);
if(dwRes == WAIT_OBJECT_0 + 2)
{
    //Quit now
    return;
}
else if(dwRes == WAIT_OBJECT_0 + 0 ||
    dwRes == WAIT_OBJECT_0 + 1)
{
    //Do reading & writing here
    ...

    //Release ownership
    ReleaseMutex(hMutex2);
    ReleaseMutex(hMutex3);
}
else
{
    //Error
}

对于乙:

DWORD dwRes = WaitForSingleObject(hMutex2, INFINITE);
if(dwRes == WAIT_OBJECT_0)
{
    //Do reading here
    ...

    //Release ownership
    ReleaseMutex(hMutex2);
}
else
{
    //Error
}

对于 C:

DWORD dwRes = WaitForSingleObject(hMutex3, INFINITE);
if(dwRes == WAIT_OBJECT_0)
{
    //Do reading here
    ...

    //Release ownership
    ReleaseMutex(hMutex3);
}
else
{
    //Error
}

有人可以确认一下吗:

  • 在两个互斥体上调用 WaitForMultipleObjects 时,它们是否都变为信号(或阻塞)?
  • 我还需要释放两个互斥锁吗?

【问题讨论】:

  • 你想要一个“读写器”锁。如果内存服务,它可以在没有 WaitForMultipleObjects 的情况下完成。 (您可能需要 WaitFSO)。我会看看我是否可以在今天晚些时候挖掘一个实现。在此之前 Bing 用于“读者作者锁定”

标签: c++ winapi synchronization mutex waitformultipleobjects


【解决方案1】:

当任何一个互斥体发出信号时,WaitForMultipleObjects 调用(第三个参数为 FALSE)将返回。这意味着作者和其中一位读者都可以获得对资源的同时访问。一个阅读器可能正在访问资源,而另一个阅读器释放其互斥锁。届时,作者将被释放。

因此,要同时使用这两个互斥锁,您需要同时等待它们。但是,您不能只将第三个参数设置为 TRUE,因为这意味着它还需要发出 hStopEvent 信号才能释放该线程(这显然是不希望的)。

一种可能是检查释放了哪个互斥锁,然后让编写者在继续之前也等待另一个互斥锁。然后它需要在完成任务后释放它们。这种类型的解决方案的一个问题是它可能会很快变得复杂,如果您添加更多需要互斥锁的进程,如果您不小心,最终可能会出现死锁。使用读写器类型的锁将大大简化处理。

编辑这并不是问题答案的一部分,但取决于所涉及的进程以及他们访问资源的频率以及他们在访问互斥锁时将持有多长时间,您可以通过使用一个互斥体并将其视为关键部分来真正简化它......每个进程在需要访问资源时都会获得它。但是,它当然不允许两个读取器线程/进程都具有并发访问权限,因此这可能是可接受的,也可能是不可接受的。但从长远来看,验证要容易得多。

【讨论】:

  • 感谢您的解释。这一切都说得通。我想现在我会尝试为 WinAPI 搜索“读写器锁定”。我很高兴在开始实施之前将其发布在这里...
  • 我认为有一些可用的,但我没有推荐。我最终根据 Jeffrey Richter 参加的演讲为 C 编写了一个读写锁。自己写可能很愚蠢,但我的同事已经对它进行了同行评审,并且使用了大约 10 年......所以我认为它正在工作。不过,我不建议您自己编写。真的很容易弄错。当时我无法找到一个可以在我当时必须处理的三种不同操作系统上运行的公开可用的操作系统。
  • 在我的情况下,读取比写入发生的频率更高,因此如果我对所有这些都使用一个互斥锁,它真的会减慢速度。至于寻找这种读写锁的实现,我得到的只是当他们使用临界区并且无法用我的停止事件方法停止等待线程时。
【解决方案2】:

您正在寻找的是读写锁。在您的算法中有一个严重的问题 - 进程 A 的饥饿:如果 B 和 C 继续工作并获取它们的互斥锁,A 可能无法进入。

【讨论】:

    【解决方案3】:

    事实上,我可以反驳它。 WaitForMultipleObjects 将waitAll 参数设置为FALSE,如果任何 个对象发出信号,则将返回。 Here's the documentation :) 将其设置为 TRUE,您将让它等待 所有 个对象。

    您的解决方案不能很好地扩展,但是:添加另一个读取线程,您会遇到第三个互斥锁...

    Writer/Readers problem 之前已经解决过很多次了;为什么不看看现有的实现?将为您节省大量调试时间,尤其是在您还不熟悉 windows 同步 API 的情况下。 (预告:posix 线程有一个读写锁,boost 有一个shared_mutex。)

    【讨论】:

    • 正如 Mark 的评论所指出的,设置为 TRUE 不起作用,因为这也会等待 hStopEvent。
    • @RaymondChen:确实;我承认,“你想要什么”有点过于乐观了 :)
    • 那么知道哪些 WinAPI 用于读写器锁吗?
    • 个人:没有经验。 Boost 有一个包含互斥体的进程间库:boost.org/doc/libs/1_49_0/doc/html/interprocess/…
    猜你喜欢
    • 2011-06-10
    • 1970-01-01
    • 2014-05-02
    • 1970-01-01
    • 2021-06-04
    • 2017-02-14
    • 1970-01-01
    • 1970-01-01
    • 2012-08-28
    相关资源
    最近更新 更多