可升级的互斥体位于 Windows 和 Linux 的共享内存中

Upgradable mutex lies at shared memory on both Windows and Linux

我在同一台机器上有 2 个名为 Writer 和 Reader 运行ning 的进程。 Writer 是一个单一的线程,将数据写入共享内存。 Reader 有 8 个线程打算并发地从共享内存中读取数据。我需要一个满足以下条件的锁定机制:

1) 一次允许Writer 或Reader 访问共享内存。

2) 如果Reader有从共享内存中读取数据的权限,那么它自己的所有线程都可以读取数据。

3) Writer 必须等到 Reader "completely" 释放锁(因为它有多个线程)。

我已经阅读了很多关于可共享互斥体的文章,这似乎是解决方案。在这里,我更详细地描述了我的系统:

1) 系统在 Windows 和 Linux 上都应 运行。

2) 我将共享内存分为两个区域:锁和数据。数据区域进一步划分为 100 个块。我打算创建 100 "lock objects"(可共享互斥体)并将它们放在锁区域。这些锁对象用于同步100个数据块,1个数据块1个锁对象。

3) 作者,Readers 首先确定要访问哪个块,然后尝试获取适当的锁。一旦获得锁,它就会对数据块执行。

我现在担心的是:

是否有任何 "built-in" 方法可以将锁定对象放置在 Windows 和 Linux (Centos) 上的共享内存上,然后我可以对这些对象执行 lock/unlock不使用 boost 库。

#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_condition.hpp>**    

//Mutex to protect access to the queue
    boost::interprocess::interprocess_mutex      mutex;

   //Condition to wait when the queue is empty
    boost::interprocess::interprocess_condition  cond_empty;

    //Condition to wait when the queue is full
    boost::interprocess::interprocess_condition  cond_full;

[编辑于 2016 年 2 月 25 日,09:30 GMT]

我可以提出一些建议。这真的取决于要求。

  1. 如果 boost 可升级互斥体看起来符合要求,那么一定要使用它。从 5 分钟阅读开始,您似乎可以在 shm 中使用它们。我没有使用它的经验,因为我不使用 boost。 Boost 在 Windows 和 Linux 上可用,所以我不明白为什么不使用它。您始终可以抓取您喜欢的特定代码并将其带入您的项目,而无需拖拽整个庞然大物。
    不管怎样,这不是很容易测试,看看它是否足够好?

  2. 我不明白在 shm 中放置锁的要求。如果没有真正的要求,并且您想使用 OS 原生 object,您可以根据 OS 使用不同的机制。比如说,在 Windows 上(不在 shm 中)命名为 mutex,在 shm 中,在 Linux.

  3. 上命名为 pthread_rwlock
  4. 我知道我更愿意使用什么:seqlock。
    我在 low-latency 域中工作,所以我正在选择让我尽可能低延迟的东西。我以 cpu 周期测量它。
    从您提到每个 object 需要一个锁,而不是一个大锁,我认为性能很重要。
    不过这里有一些重要的问题:

    • 因为它在 shm 中,我假设它是 POD(平面数据)?如果没有,您可以切换到 read/write 自旋锁。
    • 你可以旋转(忙等)还是想sleep-wait? seqlocks 和 spinlocks 没有 OS 机制,所以没有人可以让你等待的线程进入休眠状态。如果您确实想要 sleep-wait,请阅读#4
    • 如果你想知道对方 (reader/write) 死了,你必须以其他方式暗示这一点。同样,因为 seqlock 不是 OS 野兽。作为同步机制的一部分,如果你想收到另一方死亡的通知,你将不得不在 Windows 上使用命名互斥锁,在 Linux[= 上使用 shm 中的健壮互斥锁。 45=]

自旋锁和 seqlock 提供最大的吞吐量和最小的延迟。使用内核支持的同步,很大一部分延迟花费在用户和内核之间的切换 space。在大多数应用程序中,这不是问题,因为同步只在一小部分时间内发生,几微秒的额外延迟可以忽略不计。即使在游戏中,100 fps 也会让你每帧有 10 毫秒的时间,这在互斥量方面是永恒的 lock/unlock。

  1. 自旋锁的替代品通常不会贵很多。
    在Windows中,Critical Section实际上是一个带有back-off机制的自旋锁,它使用了一个Event object .这是 re-implemented 使用 shm 并命名为 Event 并调用 Metered Section
    在 Linux 中,pthread mutex 是基于 futex 的。 futex 就像 Windows 上的事件。 non-robust 没有争用的互斥量只是一个自旋锁。
    当对方死亡时,这些家伙仍然不向您提供通知。

添加 [2016 年 2 月 26 日,10:00 GMT]

如何添加自己的主人死亡检测:

Windows 命名互斥锁和 pthread 健壮互斥锁具有此功能 built-in。在使用其他锁类型时自己添加它很容易,并且在使用 user-space-based 锁时可能是必不可少的。

首先,我不得不说,在很多情况下,简单地重启一切比检测所有者的死亡更合适。这绝对更简单,因为您还必须从不是原始所有者的进程中释放锁。

无论如何,在 Windows 上检测进程死亡的本机方法很容易 - 进程是可等待的 object,因此您可以等待它们。您可以等待零时间立即检查。
在 Linux 上,只有 parent 应该知道 child 的死亡,所以不那么琐碎。 parent可以得到SIGCHILD,或者用waitpid().

我最喜欢的检测进程死亡的方法是不同的。我在两个进程之间连接了一个 non-blocking TCP 套接字,并相信 OS 在进程死亡时将其杀死。
当您尝试从套接字(在任何一侧)读取数据时,如果对等方已死亡,您将读取 0 个字节。如果它还活着,你会得到 EWOULDBLOCK.
显然,这也适用于盒子之间,所以一次性统一完成还挺方便的。

您的工作循环将不得不更改以交错对等死亡检查,这是正常工作。