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

时间:2016-02-15 08:31:31

标签: c++ multithreading mutex semaphore interprocess

我有两个名为Writer和Reader的进程在同一台机器上运行。 Writer是一个单一的线程,将数据写入共享内存。 Reader有8个线程,它们打算同时从共享内存中读取数据。我需要一种符合以下标准的锁定机制:

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

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

3)作家必须等到读者完全"释放锁(因为它有多个线程)。

我已经阅读了很多关于可共享互斥的内容,这似乎是解决方案。在这里,我将详细介绍我的系统:

1)系统应该在Windows和Windows上运行Linux操作系统。

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

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

我现在关注的是:

有没有"内置"将锁定对象放在Windows和Linux(Centos)上的共享内存上的方法然后我可以使用对象锁定/解锁而不使用boost库。

2 个答案:

答案 0 :(得分:1)

[编辑2016年2月25日,格林尼治标准时间09:30]

我可以提出一些建议。这实际上取决于要求。

  1. 如果看起来升级可升级的互斥锁符合要求,那么无论如何都要使用它。从5分钟阅读似乎你可以在shm中使用它们。我没有经验,因为我没有使用提升。 Boost可以在Windows和Linux上使用,因此我不明白为什么不使用它。您可以随时获取您喜欢的特定代码,并将其带入您的项目中,而不会拖累整个庞然大物 无论如何,测试它是否相当容易,看它是否足够好?

  2. 我不明白将锁放入shm的要求。如果它没有实际要求,并且您想要使用OS本机对象,则可以为每个OS使用不同的机制。比如说,在Linux上命名为mutex(不是shm),在Linux上命名为shm的pthread_rwlock。

  3. 我知道我更喜欢使用什么:seqlock 我在低延迟域工作,所以我选择了什么让我获得尽可能低的延迟。我在cpu周期中测量它 从你提到你想要锁定每个对象,而不是一个大锁,我认为性能很重要 但是,这里有一些重要的问题:

    • 因为它是shm,我认为是POD(平面数据)?如果没有,您可以切换到读/写螺旋锁。
    • 你是否可以旋转(忙碌的等待)或者你想睡觉 - 等待? seqlocks和spinlocks不是操作系统机制,所以没有人可以让你的等待线程进入休眠状态。如果你想睡觉等,请阅读#4
    • 如果你想知道另一方(读者/写)死了,你必须用其他方式来证明这一点。再次,因为seqlock不是OS野兽。如果您希望在同步机制中收到其他方面的死亡通知,那么您必须在Windows上使用已命名的互斥锁,以及在Linux上使用健壮的互斥锁(以shm为单位)
  4. Spinlocks和seqlocks提供最大吞吐量和最小延迟。在内核支持的同步中,延迟的很大一部分用于在用户和内核空间之间切换。在大多数应用中,这不是问题,因为同步仅在一小部分时间内发生,并且几微秒的额外延迟可忽略不计。即使在游戏中,100帧每帧也会让你每帧10毫秒,这在互斥锁定/解锁方面是永恒的。

    1. 螺旋锁的替代品通常不会贵得多 在Windows中, Critical Section 实际上是一个带有使用 Event 对象的退避机制的自旋锁。这是使用shm重命名并命名为Event并调用Metered Section 在Linux中,pthread互斥体是基于futex的。 futex就像Windows上的Event。一个没有争用的非强健互斥体只是一个自旋锁 当对方死亡时,这些家伙仍然没有通知您。
    2. 加法[2016年2月26日,格林尼治标准时间10:00]

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

      Windows名为mutex和pthread robust mutex内置了此功能。使用其他锁类型时,自己添加它很容易,并且在使用基于用户空间的锁时可能是必不可少的。

      首先,我必须说,在许多情况下,仅仅重新启动所有内容而不是检测所有者的死亡更合适。它肯定更简单,因为您还必须从不是原始所有者的进程中释放锁。

      无论如何,在Windows上检测进程死亡的本地方法很容易 - 进程是可等待的对象,因此您可以等待它们。您可以等待零时间立即检查 在Linux上,只有父母应该知道它的孩子的死亡,所以不那么琐碎。父母可以获得SIGCHILD,或使用waitpid()

      我最喜欢检测过程死亡的方法是不同的。我在两个进程之间连接一个非阻塞的TCP套接字,并信任操作系统在进程死亡时将其终止 当您尝试从套接字(在任何一侧)读取数据时,如果对等体已经死亡,则您将读取0个字节。如果它仍然存在,您将获得EWOULDBLOCK 显然,这也可以在盒子之间工作,所以很方便一劳永逸地完成它。

      你的工作循环必须改变以交错同伴死亡检查及其正常工作。

答案 1 :(得分:-2)

#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;