c++ - 如何提供对大型数组元素的线程安全访问
问题描述
我在内存中有一个非常大(数十 GB)的 mmap'd 数组,我需要提供线程安全访问。访问模式是频繁读取偶尔写入(添加)。只有几十个线程,所以碰撞的机会很低,但不是零。
我考虑过的事情:
- 我可以为每个元素创建一个互斥锁,但这在内存方面似乎很浪费。
- 我可以创建一个 unordered_set 来存储要写入的元素。如果它是一个共享锁,这并不可怕,但是每次我写一个双精度时插入和删除在运行时开销方面似乎很重
我想知道是否有一种方法可以在fetch_add
不使所有双打原子的情况下做类似的事情(特别是因为atomic<double>
大多数情况下直到 C++20 才在 C++ 中实现)。
有没有更好的方法来提供这种线程安全的访问?
解决方案
您的问题中没有提及数据的一致性,这是最重要的方面。我将尝试描述几种可能的模式,也许其中一种会满足您项目的需求。
首先,让我们想象一下,在你的巨大 mmap 中,双精度数据之间可能没有一致性:比如传感器数据,它不需要传感器之间的一致性。您可以使用atomic<double>
withatomic::store
操作:您只是存储和读取一些数据,唯一的一致性是每个元素都有新值或旧值(原子保证双精度值是一致的)。如果您需要该fetch_add
操作,您可以随时使用compare_exchange_weak
.
下一个案例:记录应该有一些一致性。您需要定义记录是什么,并shared_mutex
在每条记录的基础上拥有一个(或任何其他锁)。
另一种选择:假设您需要记录之间的一致性,但您不需要它们完全同步。类似于缓存数据的东西,这些数据最终会被更新(C++ 中的宽松内存模型)。你可能有一个shared_ptr
以实际数据为准。每个读取线程都可以复制共享指针并获得要读取的数据的所有权(这是一个廉价的操作,C++ 保证线程安全)。读取数据后,线程必须销毁共享指针的副本并释放所有权。有趣的部分是写作线程。它将数据副本创建到“交换”内存中,并且该内存由独立的共享指针拥有。写入线程更新数据,它可能需要尽可能多的时间:读取线程不知道存在“交换”并且仍然使用旧数据。一旦写入线程完成它的工作,它将shared_ptr
交换内存存储到实际的数据共享指针中。
重要的是:在写入线程提交它的工作时,仍然可能正在使用旧数据读取线程。这不是问题——他们拥有旧数据的所有权,而这些数据只是稍微过时了。无论如何,新读者都会得到更新的数据。
推荐阅读
- node.js - Discord.js 机器人做了两次
- google-sheets - 自动将复制的谷歌电子表格与原始电子表格同步
- reactjs - 在 Wavesurfer 中使用单独的 AudioContext / scriptProcessor 节点
- python - 如何用 Django 项目构建和连接 python 项目(不是 Web 应用程序)?
- python - 有没有办法在 Windows 中只获取用户帐户名?
- java - 如何更快地在 Amazon SQS 中发送消息?
- php - 使用 simplexml_load_file() 无法读取 xml 文件;
- django - createsuperuser 仅在 postgresql 上失败
- inno-setup - Inno Setup 中自定义页面画布区域的默认大小是多少?
- c# - UnityWebRequest 查询!无法将变量从 Unity 传递给 PHP