首页 > 解决方案 > 如何提供对大型数组元素的线程安全访问

问题描述

我在内存中有一个非常大(数十 GB)的 mmap'd 数组,我需要提供线程安全访问。访问模式是频繁读取偶尔写入(添加)。只有几十个线程,所以碰撞的机会很低,但不是零。

我考虑过的事情:

我想知道是否有一种方法可以在fetch_add不使所有双打原子的情况下做类似的事情(特别是因为atomic<double>大多数情况下直到 C++20 才在 C++ 中实现)。

有没有更好的方法来提供这种线程安全的访问?

标签: c++multithreadingthread-safetyc++17

解决方案


您的问题中没有提及数据的一致性,这是最重要的方面。我将尝试描述几种可能的模式,也许其中一种会满足您项目的需求。

首先,让我们想象一下,在你的巨大 mmap 中,双精度数据之间可能没有一致性:比如传感器数据,它不需要传感器之间的一致性。您可以使用atomic<double>withatomic::store操作:您只是存储和读取一些数据,唯一的一致性是每个元素都有新值或旧值(原子保证双精度值是一致的)。如果您需要该fetch_add操作,您可以随时使用compare_exchange_weak.

下一个案例:记录应该有一些一致性。您需要定义记录是什么,并shared_mutex在每条记录的基础上拥有一个(或任何其他锁)。

另一种选择:假设您需要记录之间的一致性,但您不需要它们完全同步。类似于缓存数据的东西,这些数据最终会被更新(C++ 中的宽松内存模型)。你可能有一个shared_ptr以实际数据为准。每个读取线程都可以复制共享指针并获得要读取的数据的所有权(这是一个廉价的操作,C++ 保证线程安全)。读取数据后,线程必须销毁共享指针的副本并释放所有权。有趣的部分是写作线程。它将数据副本创建到“交换”内存中,并且该内存由独立的共享指针拥有。写入线程更新数据,它可能需要尽可能多的时间:读取线程不知道存在“交换”并且仍然使用旧数据。一旦写入线程完成它的工作,它将shared_ptr交换内存存储到实际的数据共享指针中。

重要的是:在写入线程提交它的工作时,仍然可能正在使用旧数据读取线程。这不是问题——他们拥有旧数据的所有权,而这些数据只是稍微过时了。无论如何,新读者都会得到更新的数据。


推荐阅读