我使用boost映射文件库打开一个文件。 是否可以使用" fetch_add" (在某个位置读取值,然后在另一个位置添加并以原子方式写回到同一位置)?
如果多个线程并行写入,则可能存在无原子性的问题
该文件采用二进制格式,包含整数或双精度数(取决于特定文件)。
我也尝试过锁/互斥锁,但是在使用多个线程时它们总是会减慢我的程序。与算法的其余部分相比,在锁定区域中花费的时间非常大,并且线程相互阻塞。
有没有更好的方法可以让多个线程能够以高性能写入映射文件?
感谢。 拉兹
答案 0 :(得分:1)
是否有多个进程映射此文件,或只有多个线程?
如果多个进程同时访问此内存映射文件,则必须进行自己的(进程间)同步。
如果它只是多个线程,那么你可以像对任何其他内存字一样对内存进行原子更新,但需要注意的是你不能使用std::atomic
(因为显然是字节直接对应于文件中的某个部分,而不是std::atomic
个结构)。
因此,您必须使用特定平台对原子修改内存的支持,即x86上的lock xadd
,例如,Win32上的InterlockedIncrement
(或使用g ++的__sync_fetch_and_add
)。注意确保内存排序语义(和返回值!)符合您的预期。
以独立于平台的方式包装特定于平台的函数(如果您需要)可能会有点麻烦,因此在这种情况下我建议将并发访问的数据保持在单独的{{ 1}}变量,然后在结束时只更新一次相应的文件字节。
请注意,所有这些都与内存映射正交 - 操作系统将内存映射文件备份为按需交换的页面,管理这些页面的内存管理单元与内存映射文件相同。处理任意其他(非映射)页面,因此页面本身可以被多个线程修改,而不必担心除了通常的(应用程序级别)数据争用之外的任何事情。
答案 1 :(得分:1)
由于内存映射文件的行为与普通内存[1]相同,因此它可以与任何其他内存一样好用。
这个编译(使用clang++3.6 -Wall -Wextra
),但在技术上是未定义的(因为std::atomic<T>
不能保证与T
具有相同的类型或具有相同的对齐规则):
std::atomic<uint64_t> *p;
p = reinterpret_cast<std::atomic<uint64_t>*>(&dest[index]);
p->fetch_add(value);
这应该适用于g ++和clang ++:
dest[index] = __sync_fetch_and_add(&dest[index], value);
(两者都生成几乎相同的汇编代码, - 后者使用xaddq
[返回原始值],前者使用addq
- usign __sync_add_and_fetch
将执行相同的addq
1}},我希望)
[1]因为它是普通的内存 - Linux中的映射机制与处理普通内存的机制完全相同,例如当没有足够的可用内存时交换数据,或者使用代码/刚刚启动的应用程序中的数据。虽然我无法访问Windows源代码,但我相信这也是如此。其他操作系统可能会以一种略有不同的方式实现它,但没有理由相信它会阻止原子操作工作。