删除 QThreads 时检测到数据争用

Data races detected while deleting QThreads

提问人:Dazckel 提问时间:11/10/2023 最后编辑:Paul FloydDazckel 更新时间:11/10/2023 访问量:73

问:

我正在做一个多线程项目,我正在尝试使用 helgrind(valgrind 工具)检测线程不一致。

关闭应用程序后,我收到多个报告,如下所示:

==50932== Possible data race during read of size 8 at 0x3413C718 by thread #26
==50932== Locks held: none
==50932==    at 0xB91ED11: QObjectPrivate::ConnectionData::removeConnection(QObjectPrivate::Connection*) (in /usr/local/qt5/lib/libQt5Core.so.5.15.10)
==50932==    by 0xB92A4E2: QObject::~QObject() (in /usr/local/qt5/lib/libQt5Core.so.5.15.10)\
==50932==    by 0x525E9F: classA::~classA() (classA.cpp:52)
==50932==    by 0x525EC3: classA::~classA() (classA.cpp:52)
==50932==    by 0xB922012: QObject::event(QEvent*) (in /usr/local/qt5/lib/libQt5Core.so.5.15.10)
==50932==    by 0x9CC66D2: QApplicationPrivate::notify_helper(QObject*, QEvent*) (in /usr/local/qt5/lib/libQt5Widgets.so.5.15.10)
==50932==    by 0xB8F4E19: QCoreApplication::notifyInternal2(QObject*, QEvent*) (in /usr/local/qt5/lib/libQt5Core.so.5.15.10)
==50932==    by 0xB8F7F06: QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) (in /usr/local/qt5/lib/libQt5Core.so.5.15.10)
==50932==    by 0xB94EA36: ??? (in /usr/local/qt5/lib/libQt5Core.so.5.15.10)
==50932==    by 0xCCA8D3A: g_main_context_dispatch (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.7200.4)
==50932==    by 0xCCFE257: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.7200.4)
==50932==    by 0xCCA63E2: g_main_context_iteration (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.7200.4)
==50932==
==50932== This conflicts with a previous write of size 8 by thread #25
==50932== Locks held: none
==50932==    at 0xB91ED20: QObjectPrivate::ConnectionData::removeConnection(QObjectPrivate::Connection*) (in /usr/local/qt5/lib/libQt5Core.so.5.15.10)
==50932==    by 0xB92A4E2: QObject::~QObject() (in /usr/local/qt5/lib/libQt5Core.so.5.15.10)
==50932==    by 0x468CA9: IclassB::~IclassB() (IclassB.h:43)
==50932==    by 0x4646ED: classB::~classB() (classB.cpp:75)
==50932==    by 0x464711: classB::~classB() (classB.cpp:75)
==50932==    by 0xB922012: QObject::event(QEvent*) (in /usr/local/qt5/lib/libQt5Core.so.5.15.10)
==50932==    by 0x9CC66D2: QApplicationPrivate::notify_helper(QObject*, QEvent*) (in /usr/local/qt5/lib/libQt5Widgets.so.5.15.10)
==50932==    by 0xB8F4E19: QCoreApplication::notifyInternal2(QObject*, QEvent*) (in /usr/local/qt5/lib/libQt5Core.so.5.15.10)
==50932==  Address 0x3413c718 is 8 bytes inside a block of size 88 alloc'd
==50932==    at 0x484AFF5: operator new(unsigned long) (vg_replace_malloc.c:483)
==50932==    by 0xB9233E4: QObjectPrivate::connectImpl(QObject const*, int, QObject const*, void**, QtPrivate::QSlotObjectBase*, Qt::ConnectionType, int const*, QMetaObject const*) (in /usr/local/qt5/lib/libQt5Core.so.5.15.10)
==50932==    by 0xB923964: QObject::connectImpl(QObject const*, void**, QObject const*, void**, QtPrivate::QSlotObjectBase*, Qt::ConnectionType, int const*, QMetaObject const*) (in /usr/local/qt5/lib/libQt5Core.so.5.15.10)
==50932==    by 0x3E52AF: std::enable_if<QtPrivate::FunctionPointer<MainWindow::MainWindow(QWidget*)::{lambda()#31}>::ArgumentCount==(-1), QMetaObject::Connection>::type QObject::connect<void> (QObject::*)(QObject*), MainWindow::MainWindow(QWidget*)::{lambda()#31}>(QtPrivate::FunctionPointer<void> (QObject::*)(QObject*)>::Object const*, void (QObject::*)(QObject*), > QObject const*, MainWindow::MainWindow(QWidget*)::{lambda()#31}, > Qt::ConnectionType) (qobject.h:347)
==50932==    by 0x3D2149: MainWindow::MainWindow(QWidget*) (mainwindow.cpp:633)
==50932==    by 0x374017: main (main.cpp:199)
==50932==  Block was alloc'd by thread #1
==50932==

所以我有 2 个类在不同的线程中运行,当我关闭应用程序时,它们似乎都可以访问,并且由于此方法来自 Qt 框架本身,因此似乎无法解决数据竞争。QObjectPrivate::ConnectionData::removeConnection()

IclassB是接口,所以它没有实现任何内容。classB

线程 A 和 B 都访问其析构函数,它们是:

classB::~classB()
{
    if (d != nullptr)
    {
        delete d->member;
        delete d;
    }
}

classA::~classA()
{
    if (d != nullptr)
    {
        if (d->mm->isActive())
            d->mm->stop();
        delete d;
    }

}

我看不出析构函数有什么奇怪的地方。我只是想确保这个数据竞赛是误报,因为我有很多这种类型。

C++ 多线程 Qt Valgrind 数据竞赛

评论

0赞 Jesper Juhl 11/10/2023
尝试获取更多信息。此外,在终止程序之前,请始终确保您的线程已终止(通常是通过它们)。thread-sanitizerjoin
0赞 463035818_is_not_an_ai 11/10/2023
请将文本作为文本。为什么我不应该上传代码/数据/错误的图片?
1赞 hyde 11/10/2023
有一个非常具体的东西序列,这是在Qt中使用线程的正确方法。看和学习:doc.qt.io/qt-6/qthread.html
1赞 hyde 11/10/2023
不要使用 .要么使用 QObject parent,要么使用 slot(上面链接后面的示例)或使用 .没有直接使用的有效情况。deletedeleteLater()std::unique_ptrdelete
1赞 hyde 11/10/2023
在Qt中,QObject必须在正确的线程中被破坏。在线程终止之前,必须将任何具有特定线程相关性的 QObject 从该线程推送到其他线程,或者在该线程中析构。再次,例如,请参阅上一个链接。

答: 暂无答案