由于删除c++Qt多线程应用程序中的指针而导致崩溃
Crash due to delete a pointer in c++ Qt multithread application
我有一个多线程应用程序,它使用线程池,所以有10个线程运行相同的run()函数,如下所示:
run(){
...
SetTileAt(p, tile);
...
ClearPointsNotIn(list);
...
}
void TileMatrix::ClearPointsNotIn(QList<Point>list)
{
removals.clear();
mutex.lock();
foreach(Point p, matrix.keys())
{
if(!list.contains(p))
{
removals.append(p);
}
}
mutex.unlock();
foreach(Point p,removals)
{
Tile* t=TileAt(p);
if(t!=0)
{
mutex.lock();
delete t;
t=0;
matrix.remove(p);
mutex.unlock();
}
}
removals.clear();
}
void TileMatrix::SetTileAt(const Point &p, Tile* tile)
{
mutex.lock();
Tile* t=matrix.value(p,0);
if(t!=0)
delete t;
matrix.insert(p,tile);
mutex.unlock();
}
Tile* TileMatrix::TileAt(const Point &p)
{
Tile* ret;
mutex.lock();
ret=matrix.value(p,0);
mutex.unlock();
return ret;
}
当我运行应用程序时,它有时会在删除t的部分崩溃,我检查了t的值,当时它似乎是t=0,但是指向的内容完全是垃圾。我天真地猜测这是一个"删除已删除的指针问题"。但我不太确定这是怎么发生的,我如何修改代码来防止它?请注意,TileAt中的muetex与ClearPointsNotIn()中的一个muetex可能会创建死锁。。。
这是可能发生的事情,而且似乎不时发生:
很有可能,就在您在TileMatrix::ClearPointsNotIn
中获得指针t
之后,另一个线程将锁定在TileMatrix::SetTileAt
函数内的mutex.lock();
。此时,matrix.value(p,0);
可以返回与之前在控制TileMatrix::ClearPointsNotIn
的线程中返回的TileAt(p);
完全相同的指针。然后删除TileMatrix::SetTileAt
中的t
并解锁。与此同时,在运行TileMatrix::ClearPointsNotIn
函数的线程中,您在t
中有一个已经删除的指针(因为您在另一个线程中删除了它),当您对其调用delete
时,应用程序将崩溃。
这被称为竞赛条件。
我建议将mutex.lock()
语句从TileMatrix::ClearPointsNotIn
移到foreach
之后、Tile* t=TileAt(p);
之前。我还建议在删除指针后,也将0
或NULL
分配给它。这样,如果指针之前设置为0
或NULL
,if(t!=0)
将阻止执行线程执行if
内的块。请阅读此处和此处了解更多详细信息。
如果不够清楚,请告诉我,我可以提供更多细节。
正如刘柳所提到的,由于互斥对象对TileAt
的保护不足,您存在竞争条件。
ClearPointsNotIn
应该受到互斥锁的整体保护。点列表也应该通过const引用传递,而不是通过值传递。您应该使用RAII互斥锁。它可能看起来如下:
void TileMatrix::ClearPointsNotIn(const QList<Point> & list)
{
removals.clear();
QMutexLocker lock(&mutex);
foreach(Point p, matrix.keys())
{
if (!list.contains(p)) removals << p;
}
foreach(Point p, removals)
{
Tile* t = TileAt(p);
delete t;
if (t) matrix.remove(p);
}
}
此外,假设瓦片的删除没有需要持有互斥体的副作用,您可以进行重构以从互斥体下删除瓦片:
class TileMatrix {
...
QList<Tile*> deadTiles;
...
};
// Variant 1
void TileMatrix::ClearPointsNotIn(const QList<Point> & list)
{
QMutexLocker lock(&mutex);
deadTiles.clear();
foreach(Point p, matrix.keys())
{
if (list.contains(p)) continue;
Tile* tile = TileAt(p);
if (tile) {
deadTiles << tile;
matrix.remove(p);
}
}
lock.unlock();
foreach(Tile* tile, deadTiles) delete tile;
}
// Variant 2
void TileMatrix::ClearPointsNotIn(const QList<Point> & list)
{
QMutexLocker lock(&mutex);
foreach(Point p, matrix.keys())
{
if (list.contains(p)) continue;
Tile* tile = TileAt(p);
if (!tile) continue;
matrix.remove(p);
delete tile;
}
}
您应该了解变体1是否确实比变体2快。
- 为什么要增加导致崩溃的指针
- 指针相关的UE4崩溃.我的指针哪里错了?
- 访问提升:shared_ptr 主范围外崩溃,断言失败:px != 0.指针的正确用法是什么?
- 当键是虚拟继承中涉及的基类指针时,对 std::unordered_map 项的访问崩溃
- 由于指针算法错误,代码在 memcpy 中崩溃
- 使用唯一指针调用函数会使我的程序崩溃
- 智能指针的排序向量:神秘崩溃
- 类指针方法崩溃程序
- 在C++中删除指针数组时析构函数崩溃
- 使用push_back方法获取智能指针矢量时应用崩溃
- 为什么此代码在此 Trie 实现中使用映射 c++ 中的指针崩溃?
- 从 GetProcAddress 获取的函数指针在使用 stdlib 时会使程序崩溃
- 在函数内部错误定位后,从函数中释放返回的指针会导致芯片崩溃
- 为什么此自定义指针类会崩溃?
- 为什么要删除指针崩溃wchar_t?
- C 指针崩溃(非初始化)
- 删除时指针崩溃无效,但指针不同
- 指向向量元素的指针崩溃
- 函数作用域中的指针崩溃
- 为什么指针崩溃所指向的数据会增加