【发布时间】:2022-01-21 14:42:09
【问题描述】:
简单代码:
#include <iostream>
#include <random>
#include <string>
#include <map>
std::map<int, uint64_t> mp;
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> distr(1, 9);
//std::mutex _mutex;
//std::shared_timed_mutex _mutex;
std::shared_mutex _mutex;
void t1()
{
int key = 0;
uint64_t i;
while (1)
{
++key;
if (key < 1000)
{
std::map<int, uint64_t>::iterator it_mp = mp.find(key);
if (it_mp != mp.end())
{
i = distr(gen);
std::cout << "UPDATE\t1\t" << it_mp->first << "\t" << it_mp->second << "\t->\t" << i << "\n";
it_mp->second = i;
}
else
{
std::unique_lock guard(_mutex);
i = distr(gen);
std::cout << "INSERT\t1\t" << key << "\t->\t" << i << "\n";
mp.insert({ key, i });
}
}
else
{
i = distr(gen);
std::map<int, uint64_t>::iterator it_mp = mp.begin();
while (it_mp != mp.end())
{
if (it_mp->second == i)
{
std::unique_lock guard(_mutex);
std::cout << "ERASE\t1\t" << it_mp->first << "\t<-\t" << i << "\n";
it_mp = mp.erase(it_mp);
}
else
{
++it_mp;
}
}
key = 0;
}
}
}
void t2()
{
int key = 0;
uint64_t i;
while (1)
{
++key;
if (key < 1000)
{
std::map<int, uint64_t>::iterator it_mp = mp.find(key);
if (it_mp != mp.end())
{
i = distr(gen);
std::cout << "UPDATE\t2\t" << it_mp->first << "\t" << it_mp->second << "\t->\t" << i << "\n";
it_mp->second = i;
}
else
{
std::unique_lock guard(_mutex);
i = distr(gen);
std::cout << "INSERT\t2\t" << key << "\t->\t" << i << "\n";
mp.insert({ key, i });
}
}
else
{
i = distr(gen);
std::map<int, uint64_t>::iterator it_mp = mp.begin();
while (it_mp != mp.end())
{
if (it_mp->second == i)
{
std::unique_lock guard(_mutex);
std::cout << "ERASE\t2\t" << it_mp->first << "\t<-\t" << i << "\n";
it_mp = mp.erase(it_mp);
}
else
{
++it_mp;
}
}
key = 0;
}
}
}
int main()
{
std::thread _t1(t1);
_t1.detach();
std::thread _t2(t2);
_t2.join();
return 0;
}
在任意时间点发生异常(标题错误)。 有没有办法让这段代码以最小的努力工作?
我正在寻找一种在多线程环境中与 std::map 并发通信的方法。但是,Debug Assertion Failed: Expression: cannot dereference value-initialized map/set iterator.
【问题讨论】:
-
为什么
t2是一个线程?创建一个线程然后直接加入它没有意义。如果你想并行执行t1和t2,那么一个 是一个单独的线程就足够了,比如t1。然后你就直接打电话给t2。 -
而且您在没有锁定或同步的情况下使用地图,因此存在数据竞争。这意味着您的代码将具有未定义的行为。您需要保护对地图的所有访问。
-
这是一个非常大的代码中的一小部分。我一定有成千上万个这样的线程。
-
我尝试使用 std::unique_lock guard(_mutex); ......我猜没有运气。
-
您是否尝试过调试它并检查导致异常的原因?更新时不应该锁定地图吗?你不应该在其他操作中更早地锁定地图吗?例如,如果您找到一个密钥并尝试将其擦除,但另一个线程首先将其擦除,会发生什么情况?
标签: c++ insert iterator mutex erase