需求是这样的
map对象是 std::map<int, std::vector>
函数erase_by_name(std::string name),需要用迭代器it遍历map,从it->second中找到name后删除it,直到遍历完成。
int GroupByCache::erase_by_tablename(vector<string> table_name)
{
thr_scoped_spinlock _(splock);
vector<int> delete_index;
for (size_t k = 0; k < table_name.size(); k++)
{
for (auto it = caches_map.begin(); it != caches_map.end(); ++it)
{
auto &vec = it->second->table_name_vec;
if (std::find(vec.begin(), vec.end(), table_name[k]) != vec.end())
{
it = caches_map.erase(it);
}
}
}
printf("erase groupby\n");
}
表面上看没什么问题,迭代器也在删除后做了赋值,感觉自己避开了坑,很开心。
然而当map只有一个元素的时候,在erase(it)后,
it的值是map.begin(),此时map.begin()==map.end()。
for结束一次循环,++it,那么it = map.begin() + 1,不再等于map.end(),
循环继续,并且不会再停下来。
在这个项目中,锁也没有释放,就会让后面的线程全部堵在自旋锁上,cpu占用 += 100%。
出现这个问题的另一个 原因是,map没有重载大于小于比较符,只有不等于。
知道问题后,解决方法也不难。
把 ++it 作为 it 的 else 即可。
int GroupByCache::erase_by_tablename(vector<string> table_name)
{
thr_scoped_spinlock _(splock);
vector<int> delete_index;
for (size_t k = 0; k < table_name.size(); k++)
{
for (auto it = caches_map.begin(); it != caches_map.end(); )
{
auto &vec = it->second->table_name_vec;
if (std::find(vec.begin(), vec.end(), table_name[k]) != vec.end())
{
it = caches_map.erase(it);
}
else ++it;
}
}
printf("erase groupby\n");
}
题外话
可能会有人吐槽这种遍历复杂度太高N^3。
准备增加一个map<table_name, cache*>用于删除cache。
复杂度来到Nlog2N