我正在将一个对象实例传递给一个opaque模块,该模块在我的对象上执行SLOT方法(回调)。调用模块位于不同的线程上。我需要在主线程上执行方法。我以为我可以使用信号和插槽执行此操作,但信号方法仍然在调用程序线程上执行。我不认为我应该使用moveToThread()将我的对象移动到调用者线程 - 是不是有一种向我的应用程序主线程发出信号的机制?
MyClass::MyClass(...)
{
OtherClass::getInstance()->setCallback(this);
connect(this, SIGNAL(mySignalToMainThread()), this, SLOT(doThisOnMainThread()));
}
// Public slot, called by OtherClass on its own thread.
void MyClass::someCallback()
{
emit mySignalToMainThread();
}
void MyClass::doThisOnMainThread()
{
// AHHH! I am still on callers thread.
}
答案 0 :(得分:1)
起初我认为除了MyClass所在的线程上下文之外,你的信号发射可能是一个问题。但是,Qt thread documentation states:
...你可以安全地从你的QThread :: run()发出信号 实现,因为信号发射是线程安全的。
这几乎取消了这个想法。而且,您使用的是Qt::AutoConnection
,for which the documentation states:
如果信号是从与接收不同的线程发出的 对象,信号排队,表现为Qt :: QueuedConnection。 否则,直接调用插槽,表现为 Qt的:: DirectConnection。连接类型是在确定时确定的 发出信号。
最后一点特别重要。如果你要写这段代码:
void MyClass::someCallback()
{
Q_ASSERT(QThread::currentThread() != this->thread());
emit mySignalToMainThread();
}
void MyClass::doThisOnMainThread()
{
Q_ASSERT(QThread::currentThread() == this->thread());
}
我希望没有断言失败,但你建议你有一个。我不得不得出结论,Qt文档是错误的,或者这个问题比你提到的更多。
答案 1 :(得分:0)
这对我有用。也许可以将您的实施与我下面的实施进行比较,看看它可能有何不同。我试图尽可能地遵循你的惯例,猜测缺少的细节:
<强> my_class.h 强>
class MyClass : public QObject {
Q_OBJECT
public:
explicit MyClass(QObject *parent = 0);
signals:
void mySignalToMainThread();
public slots:
void someCallback();
void doThisOnMainThread();
};
<强> my_class.cpp 强>
MyClass::MyClass(QObject *parent) :
QObject(parent) {
std::cout << Q_FUNC_INFO << QThread::currentThreadId() << std::endl;
OtherClass::getInstance().setCallback(this);
connect(this, SIGNAL(mySignalToMainThread()), SLOT(doThisOnMainThread()));
}
void MyClass::someCallback() {
std::cout << Q_FUNC_INFO << QThread::currentThreadId() << std::endl;
emit mySignalToMainThread();
}
void MyClass::doThisOnMainThread() {
std::cout << Q_FUNC_INFO << QThread::currentThreadId() << std::endl;
}
<强> other_class.h 强>
class OtherClass : public QObject {
Q_OBJECT
public:
static OtherClass& getInstance();
void setCallback(MyClass *cb);
public slots:
void doCallback();
private:
explicit OtherClass(QObject *parent = 0);
MyClass *cb_;
};
<强> other_class.cpp 强>
OtherClass::OtherClass(QObject *parent) : QObject(parent) {
std::cout << Q_FUNC_INFO << QThread::currentThreadId() << std::endl;
}
OtherClass& OtherClass::getInstance() {
std::cout << Q_FUNC_INFO << QThread::currentThreadId() << std::endl;
static OtherClass singleton;
return singleton;
}
void OtherClass::doCallback() {
std::cout << Q_FUNC_INFO << QThread::currentThreadId() << std::endl;
cb_->someCallback();
}
void OtherClass::setCallback(MyClass *cb) {
std::cout << Q_FUNC_INFO << QThread::currentThreadId() << std::endl;
cb_ = cb;
}
<强>的main.cpp 强>
int main (int argc, char **argv) {
QApplication app(argc, argv);
MyClass c;
QThread other;
OtherClass::getInstance().moveToThread(&other);
other.connect(&other, SIGNAL(started()),
&OtherClass::getInstance(), SLOT(doCallback()));
other.start();
QMainWindow w;
w.show();
return app.exec();
}
示例输出:
__thiscall MyClass::MyClass(class QObject *)00001108
class OtherClass &__cdecl OtherClass::getInstance(void)00001108
__thiscall OtherClass::OtherClass(class QObject *)00001108
void __thiscall OtherClass::setCallback(class MyClass *)00001108
class OtherClass &__cdecl OtherClass::getInstance(void)00001108
class OtherClass &__cdecl OtherClass::getInstance(void)00001108
void __thiscall OtherClass::doCallback(void)000015AC
void __thiscall MyClass::someCallback(void)000015AC
void __thiscall MyClass::doThisOnMainThread(void)00001108