2014-12-06 111 views
3

我写了一个执行worker对象的线程。一切正常。所产生的信号也应该发射出去。当然,我关心线程/对象亲和力方面的常见错误。QSignalSpy不能与线程一起使用

今天我为这些工人/线程写了一个自动模块测试。我创建了一个QSignalSpy等待由工人对象(它被移到了线程)发出的这样一个信号:

QSignalSpy spy(worker, SIGNAL(Success())); 
thread.ExecuteWorker(); 
QVERIFY(spy.wait()); // Error in this line 

我得到一个公知的误差在标记行:

QObject::killTimer: timers cannot be stopped from another thread 

首先,我在我身上发现了一个错误,因为wait()中的某些代码是在错误的线程中执行的。然后我发现下面的代码QSignalSpy执行:

if (!QMetaObject::connect(obj, sigIndex, this, memberOffset, Qt::DirectConnection, 0)) 
{ 
    qWarning("QSignalSpy: QMetaObject::connect returned false. Unable to connect."); 
    return; 
} 

这显然意味着QSignalSpy使用DirectConnection所有的时间和不能被用来监测生活在不同的线程对象的信号。

他们为什么在Qt5.3中这样编程?这是一个错误还是它的打算行为?我该如何解决这个限制?

回答

3

这是不幸的是一个长期存在的问题,六年多的时间是公平的:

QSignalSpy crashes if signal is emitted from worker thread

我在Qt的贡献者峰会几年前遇到杰森,但后来他离开了诺基亚不此后诺基亚关闭了他工作的布里斯班办公室。之后,Qt的这个测试模块中没有太多的贡献,可悲的是。

有最近更多的讨论关于它的邮件列表上,太:

Why is QSignalSpy using Qt::DirectConnection?

罗兰提出的解决办法是这样的维护者,蒂亚戈,也接受:

if (thread() != QThread::currentThread()) 
{ 
    QMetaObject::invokeMethod(this, "exitLoop", Qt::QueuedConnection); 
    return; 
} 

真的有点遗憾,这在5.4之前没有进入。话虽如此,这将是固定的Qt 5.4的变化被合并:

Make QTestEventLoop::exitLoop() thread-safe

+0

我阅读了链接。特别是有趣的ML讨论。我不确定我是否完全理解了这些原因,为什么他们决定在QTestEventLoop方面解决问题,而不是在QSignalSpy连接端。两种解决方案都能解决问题,不是吗? – Silicomancer 2014-12-06 21:58:21

+0

因为维护者喜欢这种方式。 – lpapp 2014-12-07 00:56:11

1

为了使可靠地跨我用下面的办法线程QSignalSpy工作:我移动间谍工作线程和我重新实现等待功能,如下所示:

#include <QSignalSpy> 
#include <QTime> 
struct ThreadsafeQSignalSpy : QSignalSpy 
{ 
    template <typename Func> 
    ThreadsafeQSignalSpy(const typename QtPrivate::FunctionPointer<Func>::Object *obj, Func signal0) 
     : QSignalSpy(obj, signal0) 
    {} 

    bool wait(int timeout) 
    { 
     auto origCount(count()); 
     QTime timer; 
     timer.start(); 

     while (count() <= origCount && timer.elapsed() < timeout) 
      QCoreApplication::instance()->processEvents(QEventLoop::AllEvents, timeout/10); 
     return count() > origCount; 
    } 
}; 


void TestSuite::testFunction() 
{ 
    QThread thread; 
    ... 
    ThreadsafeQSignalSpy spy; 
    spy.moveToThread(thread); 
    /// now wait should work 
    ... 
    QVERIFY(spy.wait(1000)); 
} 
相关问题