在单独的线程中写入 std::map<K、V> 时需要读/写锁定

Read/Write lock required when writing to a std::map<K, V> in a separate thread

提问人:Xershy 提问时间:9/28/2022 更新时间:9/29/2022 访问量:246

问:

我在 C++ 中实现了一个 systemd 服务,该服务在系统启动时自动启动。此服务的目标是获取系统资源并使其可通过 API 访问。

其中一种资源是 CPU 负载。我实现了一个单独的线程,该线程以设定的时间间隔(每秒)从“/proc/stat”读取信息,并同时根据这些读数计算 cpu 负载。读数存储在 中,每当调用 API 时,都会从主程序中读取值。std::unordered_map<std::string, uint32_t>

我读到在不同线程中从同一容器写入和读取时,我应该使用读/写锁。这个假设正确吗?

如何实现这样的读/写锁?

映射的值是通过指定键直接写入的:my_map['some_key'] = value

如果我使用读锁锁定容器,并且单独的线程尝试同时写入,会发生什么情况?由于每秒都会写入新值,因此可能会有问题。

C++ 多线程无 序映射 ReadWriteLock

评论

0赞 lorro 9/28/2022
是的,你需要它。对于 1/sec 事务,您可能没问题(除非您强迫自己陷入死锁),只是在读锁处于活动状态时,您不会获得写锁。
0赞 Ahmed AEK 9/28/2022
对于一个,你不需要读锁,只需要一个写锁,只要确保你在读取地图时不会意外编辑地图,即:在尝试读取变量的值之前检查变量是否存在,但如果你有一个更复杂的结构,那么读/写锁将是必需的。uint32_t
2赞 Jérôme Richard 9/28/2022
@AhmedAEK 如果使用读写锁,则需要读锁来避免在写入时出现争用条件。不能保证 uint32 访问在所有平台上都是原子的(事实上,有些平台不像嵌入式 ARM 设备那样是原子的)。x86-64 保证了这一点,但不是标准。当完成调整大小或添加新值时,这也是必需的。

答:

0赞 Jérôme Richard 9/29/2022 #1

我读到在不同线程中从同一容器写入和读取时,我应该使用读/写锁。这个假设正确吗?

这不是唯一的选择,但在这种情况下,这是一个不错的选择。基本锁可以工作,但速度会变慢(它会在这里序列化读取,而读取需要快速,如果写入速度很慢,这不是问题)。

如何实现这样的读/写锁?

在 C++17 中,有一个shared_mutex类实现了这样的机制。访问模式适用于读取器,访问模式适用于写入器。sharedexclusive

如果我使用读锁锁定容器,并且单独的线程尝试同时写入,会发生什么情况?

如果容器中写入的线程没有锁定读写互斥锁的写锁,则存在导致未定义行为(例如崩溃)的争用条件。使用读写锁,对容器的写入将是互斥的(即安全)。在读取和写入之间发生相同的 ting,但在多次读取之间不会发生。