2012-01-06 136 views
9

我有一个共享内存之间的多个进程以特定方式插入内存。 例如:原子访问共享内存

DataBlock { 
int counter; 
double value1; 
double ... } 

我要的是计数器进行更新/原子递增。并在该地址发生内存释放。 如果我使用的werent共享内存,例如,它会像

std::atomic<int> counter; 
atomic_store(counter, newvalue, std::memory_order_release); // perform release  operation on the affected memory location making the write visible to other threads 

如何做到这一点的随机存储位置(解释为数据块计数器>以上)。我可以保证该地址按照架构(x86 linux)的要求对齐

  1. 使更新原子化 - 如何? (即atomicupdate(addr,newvalue))
  2. 内存同步多核 - (即memorysync(addr)) - 我可以看到的唯一方法是使用std :: atomic_thread_fence(std :: memory_order_release) - 但这将“建立内存所有原子和放松的原子商店的同步排序“ - 这对我来说是过度的 - 我只想让计数器位置同步。 欣赏任何想法。
+3

我只是猜测,但我的印象是,C++编程模型没有“进程”的概念,内存模型没有“共享内存”的概念,所以我怀疑标准本身会使任何保证。共享内存非常依赖于平台功能,因此请查阅您的平台文档。 – 2012-01-06 14:59:51

+0

你可以在你的DataBlock中放入一个'atomic '吗?只要'atomic '是无锁的(标准显式提及内存在进程间共享作为这些用例的用例),这应该工作。不,你不能只是得到一个随机地址原子(见http://stackoverflow.com/questions/8749038/how-to-use-stdatomic-efficiently/8749474)@Kerrek SB:实际上,这种情况被提及[atomics.lockfree]在最后的草稿中。 – Grizzly 2012-01-06 15:22:46

+0

@Grizzly:你的意思是非规范性说明29.4/3?非常有趣,我不知道。 – 2012-01-06 15:26:40

回答

-2

您可以使用锁&等待机制,增加计数器。 Boost库提供了一个锁定和等待机制。检查这个链接reference

9

我无法用这里的权威回答,但我可以提供可能有帮助的相关信息。

  1. 互斥量可以在共享内存中创建和/或创建为跨进程。 Pthread有一个特殊的创建标志,我不记得是否使用共享内存,或者你共享一个句柄。 linux“futex”可以直接使用共享内存(注意用户地址可能不同,但底层实际地址应该是相同的)

  2. 硬件原子工作在内存上而不是过程变量。也就是说,你的芯片不会关心哪些程序正在修改变量,因此最低级别的原子将会自然地跨进程。这同样适用于围栏。

  3. C++ 11无法指定跨进程原子。但是,如果它们是无锁的(检查标志),很难看到编译器如何实现它们,从而使跨进程无法工作。但是你会对你的工具链和最终平台产生很大的信心。

  4. CPU依赖性保证还会跟踪实际内存地址,因此只要您的程序在线程化形式下正确,它的多进程形式(关于可见性)也应该是正确的。

  5. Kerrek是正确的,抽象机器没有提到多个进程。但是,它的同步细节的编写方式使得它们同样适用于跨进程,就像它们对多线程所做的一样。这与#3有关:编译器很难将其搞砸。

简而言之,没有符合标准的方法可以做到这一点。然而,依靠标准定义多线程的方式,可以为质量编译器做出很多假设。

最大的问题是一个原子是否可以简单地分配到共享内存中(放置新的)并工作。显然这只有在它是一个真正的硬件原子时才有效。然而,我的猜测是,对于高质量的编译器/库文件,C++原子应该在共享内存中工作。

玩得开心验证行为。 :)

4

既然你是在Linux上,你可以使用gcc原子内置__sync_fetch_and_add()上的地址为counter ......根据gcc-documentation on atomic built-ins,这也将实行全方位的存储栅栏,不释放操作,但是由于你实际上需要一个读 - 修改 - 写操作而不是简单的加载(例如,增加一个计数器不仅仅是一个负载,而且你必须读取,然后修改并最终回写该值)内存围栏将成为执行此操作的正确内存排序的更好选择。

+0

'__sync_fetch_and_add()'可以使用,但我认为'__sync_sub_and_fetch()'更合适。你减少引用计数,并释放,如果它下降到零。它保证,如果两个线程同时从2递减,只有一个将返回0(并且将释放)。 – ugoren 2012-01-06 20:30:02

+0

这绝对是一个很好的建议...一个原子内置将用于复制过程中的增量等,另一个用于在不再使用该引用时降低该值。 – Jason 2012-01-06 21:15:41