问题标签 [shared-memory]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
1 回答
2380 浏览

c++ - 为什么创建由不同进程共享的环形缓冲区如此困难(在 C++ 中),我做错了什么?

我对此特别密集,但似乎我错过了一个重要的基本点或其他东西,因为我想做的事情应该是常见的:

我需要从管理器进程 ( Process M) 创建一个固定大小的环形缓冲区对象。该对象具有从缓冲区写入/读取的方法write()read()读/写方法将由独立进程(Process RW)调用

我已经实现了缓冲区,SharedBuffer<T&>它使用 boost::interprocess 在 SHM 中分配缓冲区插槽,并在单个进程中完美运行。我已经阅读了这个问题的答案以及关于 SO 的答案以及我自己的问题,但我仍然对如何从一个公共对象有不同的进程访问方法一无所知。Boost 文档有一个在 SHM 中创建向量的示例,这与我想要的非常相似,但我想实例化我自己的类。

我目前的选择是:

  1. new正如 Charles B. 对我的问题所建议的那样,使用放置位置;但是,他警告说,将非 POD 对象放在 SHM 中并不是一个好主意。但是我的班级需要读/写方法,我该如何处理?
  2. 在我的类定义中添加一个分配器,例如,拥有SharedBuffer<T&, Alloc>并继续类似于boost 中给出的向量示例。这听起来真的很复杂。
  3. 更改SharedBuffer为 POD 类,即去掉所有方法。但是那么如何在进程之间同步读写呢?

我错过了什么?固定长度的环形缓冲区很常见,所以要么这个问题有解决方案,要么我做错了什么。

0 投票
1 回答
1445 浏览

c++ - 在共享内存中使用自定义分配器实例化类

由于以下问题,我正在拉扯我的头发:我正在按照boost.interprocess 文档中给出的示例来实例化我在共享内存中编写的固定大小的环形缓冲区缓冲区类。我的类的骨架构造函数是:

我的第一个问题:这种分配是否保证缓冲区节点分配在连续的内存位置,即当我尝试从m_start_ptr + n*sizeof(BufferNode)我的Read()方法中的地址访问第 n 个节点时它会起作用吗?如果没有,有什么更好的方法来保留节点,创建一个链表?

我的测试工具如下:

这给了我与最后一条语句的模板相关的各种编译错误。我究竟做错了什么?segment.construct<MyBuf>("MyBuffer")(100, alloc_inst)提供两个模板参数的正确方法是什么?

0 投票
1 回答
581 浏览

c++ - 如何在 Boost.Interprocess 中将参数传递给 manage_shared_memory.construct()

我已经盯着 Boost.Interprocess 文档看了好几个小时,但仍然无法弄清楚这一点。在文档中,他们有一个在共享内存中创建向量的示例,如下所示:

现在,我明白了这一点。我被卡住的是如何传递第二个参数segment.construct()来指定元素的数量。进程间文档给出了construct()as的原型

但是当我尝试

我得到编译错误。

我的问题是:

  1. 谁实际上是从对象的构造函数传递参数par1, par2segment.construct,例如vector?我的理解是正在传递模板分配器参数。那是对的吗?
  2. alloc_inst除了在共享内存中创建的对象的构造函数所要求的之外,我如何添加另一个参数?

除了简洁的 Boost 文档之外,几乎没有关于此的信息。

0 投票
1 回答
691 浏览

c++ - 关于共享内存中 C++ 容器类的快速设计问题

我正在围绕 boost::interprocess 的向量容器编写一个简单的包装器,以在 IPC 的共享内存 (shm) 中实现一个环形缓冲区。假设这是一个在 shmbuf中创建的实例。RingBuffer现在,在它的 ctor 中,buf它本身分配了一个私有boost::interprocess::vector数据成员来存储值,例如m_data. 我的问题是:我认为m_data也应该在共享内存中创建。但这是必需品吗?

如果buf它是在 shm 本身中创建的,会分配标准内存,即使用new. 这是否在调用进程的堆上分配?我不认为buf是在那里分配的,所以为什么不在进程堆上的对象私有的数据成员会在那里分配。我很困惑。

0 投票
3 回答
484 浏览

c++ - Can you force a crash if a write occurs to a given memory location with finer than page granularity?

I'm writing a program that for performance reasons uses shared memory (sockets and pipes as alternatives have been evaluated, and they are not fast enough for my task, generally speaking any IPC method that involves copies is too slow). In the shared memory region I am writing many structs of a fixed size. There is one program responsible for writing the structs into shared memory, and many clients that read from it. However, there is one member of each struct that clients need to write to (a reference count, which they will update atomically). All of the other members should be read only to the clients.

Because clients need to change that one member, they can't map the shared memory region as read only. But they shouldn't be tinkering with the other members either, and since these programs are written in C++, memory corruption is possible. Ideally, it should be as difficult as possible for one client to crash another. I'm only worried about buggy clients, not malicious ones, so imperfect solutions are allowed.

I can try to stop clients from overwriting by declaring the members in the header they use as const, but that won't prevent memory corruption (buffer overflows, bad casts, etc.) from overwriting. I can insert canaries, but then I have to constantly pay the cost of checking them.

Instead of storing the reference count member directly, I could store a pointer to the actual data in a separate mapped write only page, while keeping the structs in read only mapped pages. This will work, the OS will force my application to crash if I try to write to the pointed to data, but indirect storage can be undesirable when trying to write lock free algorithms, because needing to follow another level of indirection can change whether something can be done atomically.

Is there any way to mark smaller areas of memory such that writing them will cause your app to blow up? Some platforms have hardware watchpoints, and maybe I could activate one of those with inline assembly, but I'd be limited to only 4 at a time on 32-bit x86 and each one could only cover part of the struct because they're limited to 4 bytes. It'd also make my program painful to debug ;)

Edit: I found this rather eye popping paper, but unfortunately it requires using ECC memory and a modified Linux kernel.

0 投票
5 回答
5675 浏览

multithreading - 是否可以在不使用偏移量的情况下将指针存储在共享内存中?

当使用共享内存时,每个进程可以将共享区域映射到其各自地址空间的不同区域。这意味着当在共享区域中存储指针时,您需要将它们存储为共享区域开始的偏移量。不幸的是,这使原子指令的使用变得复杂(例如,如果您正在尝试编写无锁算法)。例如,假设您在共享内存中有一堆引用计数节点,由单个作者创建。编写器定期自动更新指针“p”以指向具有正引用计数的有效节点。读者希望以原子方式写入“p”,因为它指向一个节点(结构)的开头,该节点的第一个元素是引用计数。由于 p 总是指向一个有效的节点,增加 ref 计数是安全的,并且可以安全地取消引用 'p' 并访问其他成员。然而,这一切只有在所有东西都在同一个地址空间中时才有效。如果节点和“p”指针存储在共享内存中,则客户端会遇到竞争条件:

  1. x = 读取 p
  2. y = x + 偏移量
  3. 在 y 处增加引用计数

在第 2 步期间,p 可能会发生变化,并且 x 可能不再指向有效节点。我能想到的唯一解决方法是以某种方式强制所有进程就映射共享内存的位置达成一致,以便可以将真正的指针而不是偏移量存储在 mmap'd 区域中。有没有办法做到这一点?我在 mmap 文档中看到 MAP_FIXED,但我不知道如何选择一个安全的地址。

编辑:在 x86 上使用内联汇编和“锁定”前缀也许可以构建一个“增量 ptr X,偏移量 Y 值 Z”?其他架构上的等效选项?没有写很多汇编,不知道有没有需要的指令。

0 投票
4 回答
19774 浏览

sql-server - 无法连接到 SQL Server 2008 - 看起来像是共享内存问题

我无法使用 SQL Server Management Studio 连接到我的本地 SQL Server 2008 Express 实例。

我相信这个问题与我对连接协议所做的更改有关。在错误发生之前,我启用了共享内存并禁用了命名管道和 TCP/IP。然后我启用了命名管道和 TCP/IP,这就是我开始遇到问题的时候。

当我尝试使用 SSMS(使用我的 SQL 服务器系统管理员登录或 Windows 身份验证)连接到服务器时,我收到以下错误消息:

与服务器成功建立连接,但在登录过程中出现错误。(提供者:命名管道提供者,错误:0 - 管道的另一端没有进程。)(Microsoft SQL Server,错误:233)

为什么它返回命名管道错误?为什么它不只使用共享内存,因为它在连接协议列表中具有更高的优先级顺序?似乎由于某种原因它没有在共享内存上监听?

当我将命名管道设置为启用并尝试连接时,我收到相同的错误消息。

我的 Windows 帐户在我的计算机上没有管理员权限 - 也许这在某种程度上有所不同(正如本文中 关于“SuperSocketNetLib\Lpc”注册表项的一些讨论所暗示的那样)。

0 投票
3 回答
334 浏览

c++ - 为什么一个循环比另一个循环检测共享内存更新需要更长的时间?

我编写了一个写入共享内存的“服务器”程序,以及一个从内存中读取的客户端程序。服务器有不同的“通道”可以写入,它们只是不同的链接列表,它也可以附加项目。客户端对某些链表感兴趣,并希望读取添加到这些链表中的每个节点,并尽可能降低延迟。

我有两种方法供客户使用:

  1. 对于每个链表,客户端保留一个“书签”指针以保持其在链表中的位置。它循环循环链表,一遍又一遍地遍历所有链表(它永远循环),如果可以的话,每次将每个书签向前移动一个节点。是否可以由节点的“下一个”成员的值确定。如果它是非空的,那么跳转到下一个节点是安全的(服务器自动将它从空切换到非空)。这种方法工作正常,但是如果有很多列表要迭代,并且只有少数列表正在接收更新,那么延迟就会变差。

  2. 服务器给每个列表一个唯一的 ID。每次服务器将项目附加到列表时,它也会将列表的 ID 号附加到主“更新列表”。客户端只保留一个书签,一个书签到更新列表中。它无休止地检查书签的下一个指针是否为非空(while(node->next_ == NULL) {}),如果是,则继续读取给定的 ID,然后处理链表上具有该 ID 的新节点。从理论上讲,这应该可以更好地处理大量列表,因为客户端不必每次都遍历所有列表。

当我对这两种方法的延迟进行基准测试时(使用 gettimeofday),令我惊讶的是#2 非常糟糕。对于少量链表,第一种方法的延迟通常低于 20us。第二种方法会有少量低延迟,但通常在 4,000-7,000us 之间!

通过在这里和那里插入 gettimeofday,我确定方法 #2 中所有增加的延迟都花在循环中,反复检查下一个指针是否为非空。这让我很困惑;就好像一个流程中的更改需要更长的时间才能使用第二种方法“发布”到第二个流程。我假设正在进行某种我不明白的缓存交互。这是怎么回事?

更新:最初,方法 #2 使用条件变量,因此如果node->next_ == NULL它会等待条件,服务器会在每次发布更新时通知该条件。延迟是相同的,并且试图弄清楚为什么我将代码减少到上述方法。我在多核机器上运行,所以一个进程自旋锁不应该影响另一个。

更新 2: node->next_ 是不稳定的。

0 投票
4 回答
801 浏览

c++ - 在这 3 种从共享内存中读取链表的方法中,为什么第三快?

我有一个“服务器”程序,可以更新共享内存中的许多链接列表以响应外部事件。我希望客户端程序尽快注意到任何列表的更新(最低延迟)。服务器将链表的节点标记state_FILLED一旦其数据被填充并且其下一个指针已设置为有效位置。在那之前,它state_NOT_FILLED_YET。我正在使用内存屏障来确保客户端不会state_FILLED以前一样看到其中的数据实际上已经准备好(而且它似乎有效,我从来没有看到损坏的数据)。此外,state_它是不稳定的,以确保编译器不会将客户端的检查从循环中解除。

保持服务器代码完全相同,我为客户端提供了 3 种不同的方法来扫描链接列表以进行更改。问题是:为什么第三种方法最快?

方法 1:连续循环遍历所有链表(称为“通道”),查看是否有任何节点已更改为“已填充”:

当通道数量很少时,方法 1 的延迟非常低。但是当频道数量增加(250K+)时,由于循环遍历所有频道,它变得非常慢。于是我试了...

方法二:给每个链表一个ID。在旁边保留一个单独的“更新列表”。每次更新链表之一时,将其 ID 推送到更新列表。现在我们只需要监控单个更新列表,并检查我们从中获得的 ID。

方法 2 给出了可怕的延迟。方法 1 可能会给出低于 10 毫秒的延迟,而方法 2 会莫名其妙地经常给出 8 毫秒的延迟!使用 gettimeofday 似乎 update_cursor->state_ 的变化从服务器的视图传播到客户端的视图非常缓慢(我在一个多核机器上,所以我认为延迟是由于缓存造成的)。所以我尝试了一种混合方法......

方法三:保留更新列表。但是不断循环遍历所有通道,并在每次迭代中检查更新列表是否已更新。如果有,请使用推到其上的号码。如果没有,请检查我们当前迭代到的通道。

此方法的延迟与方法 1 一样好,但可以扩展到大量通道。问题是,我不知道为什么。只是为了解决问题:如果我取消注释“通过更新找到”部分,它会在每个延迟日志消息之间打印。这意味着东西只能在更新列表中找到!所以我不明白这种方法如何比方法2更快。

生成随机字符串作为测试数据的完整可编译代码(需要 GCC 和 boost-1.41)位于: http: //pastebin.com/0kuzm3Uf

更新:所有 3 种方法都有效地自旋锁定,直到发生更新。不同之处在于他们注意到更新发生需要多长时间。它们不断地对处理器征税,因此这并不能解释速度差异。我正在一台 4 核机器上进行测试,没有其他任何东西在运行,所以服务器和客户端没有什么可竞争的。我什至制作了一个代码版本,其中更新表示条件并让客户端等待条件 - 它无助于任何方法的延迟。

Update2:尽管有 3 种方法,但我一次只尝试了 1 种,因此只有 1 个服务器和 1 个客户端在竞争 state_ 成员。

0 投票
2 回答
325 浏览

apache2 - 如何在共享内存段中创建 apr_table_t 类型的表?

如何在共享内存段中创建 apr_table_t 类型的表?