2014-12-06 6 views
3

Я написал поток, который выполняет рабочий объект. Все работает нормально. Также результирующие сигналы испускаются так, как должны. Конечно, я позаботился о обычных ошибках в отношении близости ниток/объектов.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

я встретил Джейсон на Contributor Summit Qt пару лет назад, но тогда он оставил Nokia не после этого, когда Nokia закрыла офис в Брисбене, где он работал. После этого, в этом тестовом модуле Qt, к сожалению, не так много.

Был недавно больше обсуждения об этом в списке рассылки, тоже:

Why is QSignalSpy using Qt::DirectConnection?

Решение, предложенное Roland было это, что сопровождающий, Тьяго, также принимаются:

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

+0

Потому что поддерживателю это нравилось. – lpapp

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)); 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^