std::map::end 线程安全,并保证它对于同一容器始终相同
Is std::map::end thread-safe and is guaranteed that it always the same for the same container?
我使用std::map
并得到一个我可以使用的元素:http://www.cplusplus.com/reference/map/map/
-
iterator find (const key_type& k);
-
mapped_type& at (const key_type& k);
-
mapped_type& operator[] (const key_type& k);
另外:在这种情况下,lower_bound()
或equal_range()
- 与find()
相同。
我不能使用:
-
at()
- 因为它抛出异常,并且我测量了 10 倍的性能下降 -
operator[]
- 因为它插入一个元素(如果不存在),所以这种行为是不可接受的
find()
- 是我想要的。但是我在多线程程序中使用std::map
并通过锁定std::mutex
来保护它。
还可以插入和删除以从其他线程std::map
。
我应该保护std::map::end
还是保证一个分配的容器始终相同?
我可以使用这样不受std::mutex
保护的static auto const map_it_end = map1.end();
的东西吗?
http://ideone.com/tATn0H
#include <iostream>
#include <string>
#include <mutex>
#include <thread>
#include <map>
std::map<std::string, std::string> map1 ( {{"apple","red"},{"lemon","yellow"}} );
static auto const map_it_end = map1.end();
std::mutex mtx1;
void func() {
std::lock_guard<std::mutex> lock1(mtx1);
auto it1 = map1.find("apple");
if(it1 != map_it_end) // instead of: if(it1 != map1.end())
std::cout << it1->second << ", ";
}
int main ()
{
std::thread t1(func);
std::thread t2(func);
t1.join();
t2.join();
return 0;
}
http://www.cplusplus.com/reference/map/map/end/
数据竞赛 容器被访问(既不是常量也不是 非常量版本修改容器)。不包含任何元素 由调用访问,但返回的迭代器可用于访问 或修改元素。同时访问或修改不同的 元素是安全的。
我应该保护
std::map::end
还是保证一个分配的容器始终相同?
从技术上讲,如果对成员函数的任何调用可能与任何非常量成员函数同时发生,则必须受互斥锁保护。因此,如果任何线程可能插入或擦除元素,那么在不锁定互斥锁的情况下调用end()
是不安全的。
在某些情况下,您可以缓存过去结束迭代器我可以使用这样不受
std::mutex
保护的static auto const map_it_end = map1.end();
的东西吗?
,因为std::map
的过去结束迭代器不会因插入和擦除而失效,只是可能通过交换或移动映射而失效。
但是你为什么要这样做呢?缓慢的操作find()
不end()
,所以如果你在仍然持有互斥锁的同时调用end()
,那么它肯定有效。
如果其他线程可能正在擦除元素,那么在取消引用 find()
返回的迭代器时,您需要持有互斥锁,以确保它不会被另一个线程擦除它引用的元素而失效。因此,当您已经锁定互斥锁时,调用end()
不会成为问题。
我在23.2 Container requirements
中找不到任何指定end()
始终返回相同值的内容,也没有发现它是线程安全的。 end()
定义如下。
begin() 返回一个迭代器,引用 容器。end() 返回一个迭代器,它是过去的结束值 对于容器。如果容器为空,则 begin() == end();
此规范似乎涵盖了所有容器的end()
。我在23.4.4 Class template map
中找不到任何可以取代此一般容器要求的内容。实际上,"过去结束值"的措辞是这样的,因此可以合理地解释为end()
的值可能会根据容器中最后一个元素的位置而变化。
这将是std::vector
的典型情况.一个典型的std::vector
end()
值会根据向量中元素的数量而变化,原因很明显。没有任何规定必须这样做,但通常是这种情况。回到std::map
,人们可能会期望给定地图的end()
总是相同的值,但也没有说明它必须这样做。
我想说的是,对std::map
的所有访问都必须受到互斥锁的保护。一旦互斥锁被释放,关于映射的任何内容都不再有效。不能假设end()
在互斥锁发布后仍将是有效的迭代器。
- C++:在多个线程中访问同一数组/向量的不同单元格是否会产生数据竞赛?
- 多个线程可以安全地同时将相同的值写入同一变量吗?
- 适用于大型数组的无复制线程安全环形缓冲区
- 当 2 个线程共享同一物理内核时,具有错误共享的易失性增量在发布中的运行速度比在调试中慢
- 多个线程可以同时在同一接口上嗅探吗?
- __thread Embarcadero c++ 10.1 中不创建特定于线程的变量
- Opencv cpp 使用多线程处理同一视频的不同部分
- 为同一向量C++运行多个线程时出现分段错误
- 线程 1 从文件读取,就像线程 2 写入同一文件一样
- 多线程可以访问同一weak_ptr对象C++吗?
- 对于同一任务,线程的等待时间在 0 到 30000 微秒之间系统地切换
- OpenMP:共享同一算法的单线程和多线程实现
- 条件_variable和unique_lock如何适用于线程安全列表
- 可以在同一条件变量上等待多个线程
- 当两个线程同时尝试在同一静音上尝试try_lock()时会发生什么
- 当并行线程访问同一数据结构的其他成员时,正确的方法可以在Visual Studio上的OpenMP上并行循环
- 为什么 gui 线程不应该存在于多线程单元中?
- 在OpenMP中屈服于其他线程/任务
- 适用于工作线程的螺纹"fence"
- 如何循环访问特定于提升线程的指针