[英]Qt moveToThread and data races
有一個帶有一個信號和插槽的類:
#ifndef SOME_CLASS_H
#define SOME_CLASS_H
#include <QObject>
class SomeClass : public QObject
{
Q_OBJECT
public:
explicit SomeClass(QObject *parent = 0) : QObject(parent) {
connect(this, &SomeClass::valueChanged, this, &SomeClass::setValue);
}
void emitSignal() {
emit valueChanged();
}
signals:
void valueChanged();
public slots:
void setValue() {}
};
#endif // SOME_CLASS_H
這是定義單例的程序主文件,該單例創建上述定義的類的實例並將其放入單獨的線程中:
#include <QCoreApplication>
#include <QThread>
#include <someclass.h>
class Singleton {
public:
QThread t;
SomeClass someClassObject;
Singleton() {
someClassObject.moveToThread(&t);
t.start();
}
static SomeClass& getInstance() {
static Singleton st;
return st.someClassObject;
}
~Singleton() {
t.quit();
t.wait();
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
SomeClass& b = Singleton::getInstance();
b.emitSignal();
QThread::msleep(100);
return a.exec();
}
問題是,當我使用某些線程檢查工具(例如ThreadSanitizer或Helgrind)評估該程序時,會報告一些有關數據爭用情況的警告。 ThreadSanitizer的示例輸出:
==================
WARNING: ThreadSanitizer: data race (pid=3827)
Read of size 8 at 0x7d040000f6a0 by thread T1:
#0 void QtPrivate::FunctionPointer<void (SomeClass::*)()>::call<void, void>(void (SomeClass::*)(), SomeClass*, void**) /usr/include/qt5/QtCore/qobjectdefs_impl.h:142 (exe+0x0000000a2d1c)
#1 QtPrivate::QSlotObject<void (SomeClass::*)(), void, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) /usr/include/qt5/QtCore/qobject_impl.h:149 (exe+0x0000000a29b4)
#2 QObject::event(QEvent*) ??:0 (libQt5Core.so.5+0x00000029022d)
Previous write of size 8 at 0x7d040000f6a0 by main thread:
#0 malloc ??:0 (exe+0x0000000426e9)
#1 QMetaObject::activate(QObject*, int, int, void**) ??:0 (libQt5Core.so.5+0x00000028ef1c)
#2 main /tmp/project/main.cpp:31 (exe+0x0000000a19f2)
Location is heap block of size 8 at 0x7d040000f6a0 allocated by main thread:
#0 malloc ??:0 (exe+0x0000000426e9)
#1 QMetaObject::activate(QObject*, int, int, void**) ??:0 (libQt5Core.so.5+0x00000028ef1c)
#2 main /tmp/project/main.cpp:31 (exe+0x0000000a19f2)
Thread T1 'QThread' (tid=3829, running) created by main thread at:
#0 pthread_create ??:0 (exe+0x000000046f6b)
#1 QThread::start(QThread::Priority) ??:0 (libQt5Core.so.5+0x0000000928b7)
#2 Singleton::getInstance() /tmp/project/main.cpp:16 (exe+0x0000000a1b3c)
#3 main /tmp/project/main.cpp:30 (exe+0x0000000a19bf)
SUMMARY: ThreadSanitizer: data race /usr/include/qt5/QtCore/qobjectdefs_impl.h:142 void QtPrivate::FunctionPointer<void (SomeClass::*)()>::call<void, void>(void (SomeClass::*)(), SomeClass*, void**)
==================
==================
WARNING: ThreadSanitizer: data race (pid=3827)
Write of size 1 at 0x7d040000f6b0 by thread T1:
#0 free ??:0 (exe+0x000000042dfb)
#1 QMetaCallEvent::~QMetaCallEvent() ??:0 (libQt5Core.so.5+0x00000028d3a4)
Previous write of size 8 at 0x7d040000f6b0 by main thread:
#0 malloc ??:0 (exe+0x0000000426e9)
#1 QMetaObject::activate(QObject*, int, int, void**) ??:0 (libQt5Core.so.5+0x00000028eefe)
#2 main /tmp/project/main.cpp:31 (exe+0x0000000a19f2)
Location is heap block of size 4 at 0x7d040000f6b0 allocated by main thread:
#0 malloc ??:0 (exe+0x0000000426e9)
#1 QMetaObject::activate(QObject*, int, int, void**) ??:0 (libQt5Core.so.5+0x00000028eefe)
#2 main /tmp/project/main.cpp:31 (exe+0x0000000a19f2)
Thread T1 'QThread' (tid=3829, running) created by main thread at:
#0 pthread_create ??:0 (exe+0x000000046f6b)
#1 QThread::start(QThread::Priority) ??:0 (libQt5Core.so.5+0x0000000928b7)
#2 Singleton::getInstance() /tmp/project/main.cpp:16 (exe+0x0000000a1b3c)
#3 main /tmp/project/main.cpp:30 (exe+0x0000000a19bf)
SUMMARY: ThreadSanitizer: data race ??:0 free
==================
==================
WARNING: ThreadSanitizer: data race (pid=3827)
Write of size 8 at 0x7d180000edc0 by thread T1:
#0 operator delete(void*) ??:0 (exe+0x00000004392b)
#1 QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) ??:0 (libQt5Core.so.5+0x000000269e0f)
Previous write of size 8 at 0x7d180000edc0 by main thread:
#0 operator new(unsigned long) ??:0 (exe+0x0000000432b9)
#1 QMetaObject::activate(QObject*, int, int, void**) ??:0 (libQt5Core.so.5+0x00000028ef94)
#2 main /tmp/project/main.cpp:31 (exe+0x0000000a19f2)
Location is heap block of size 88 at 0x7d180000edc0 allocated by main thread:
#0 operator new(unsigned long) ??:0 (exe+0x0000000432b9)
#1 QMetaObject::activate(QObject*, int, int, void**) ??:0 (libQt5Core.so.5+0x00000028ef94)
#2 main /tmp/project/main.cpp:31 (exe+0x0000000a19f2)
Thread T1 'QThread' (tid=3829, running) created by main thread at:
#0 pthread_create ??:0 (exe+0x000000046f6b)
#1 QThread::start(QThread::Priority) ??:0 (libQt5Core.so.5+0x0000000928b7)
#2 Singleton::getInstance() /tmp/project/main.cpp:16 (exe+0x0000000a1b3c)
#3 main /tmp/project/main.cpp:30 (exe+0x0000000a19bf)
SUMMARY: ThreadSanitizer: data race ??:0 operator delete(void*)
==================
是什么原因導致這些比賽條件?
由於警告全部源自與信號,插槽和事件循環有關的Qt內部,因此我認為檢測到的競爭條件是誤報。 Helgrind是否檢測到相同的比賽條件? 一些人報告了Qt的Helgrind錯誤( http://www.kdab.com/~dfaure/helgrind.html ),並且似乎在最近得到了解決。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.