2014-12-06 8 views
3

작업자 개체를 실행하는 스레드를 작성했습니다. 모든 것이 잘 작동합니다. 또한 결과 신호는 필요한대로 방출됩니다. 물론 스레드/객체 연관성에 관한 일반적인 실수를 처리했습니다.QSignalSpy를 스레드와 함께 사용할 수 없습니다.

오늘 나는 그 근로자/스레드에 대한 자동화 된 모듈 테스트를 작성했습니다.

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

I은 ​​마크 된 라인에 잘 알려진 에러를 얻고 :

QObject::killTimer: timers cannot be stopped from another thread 
I는 다음과 같이 (스레드로 이동 된) 작업자 물체에 의해 방사되는 신호를 기다려야하는 QSignalSpy 만들어

먼저 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

이 불행하게도 오랜 문제, 6 년 이상이 공정하게 :

QSignalSpy crashes if signal is emitted from worker thread

나는 몇 년 전 Qt는 기여자 정상 회의에서 제이슨을 만났지만 그는 노키아를하지 왼쪽 그 후 Nokia는 그가 일하고있는 브리즈번 사무실을 폐쇄했다. 그 후, Qt의이 테스트 모듈에서 진행되는 많은 기여는 없었습니다. 슬프게도.

도 메일 링리스트에 대해 최근 많은 논의가 있었다 : 롤랜드에 의해 제안 된

Why is QSignalSpy using Qt::DirectConnection?

이 솔루션은 프로젝트 관리자가, 티아고는 또한 받아 들였다이 있었다 :

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

이것은 5.4 이전에 들어 가지 않았기 때문에 정말로 수치 스럽습니다.

Make QTestEventLoop::exitLoop() thread-safe

+0

나는 링크를 읽습니다. 흥미 진진한 ML 디스코션. QSignalSpy가 아니라 QTestEventLoop 쪽에서 문제를 해결하기로 결정한 이유를 완전히 이해했는지 확신 할 수 없습니다. 두 가지 해결책 모두 문제를 해결했을 것입니다. 그렇지 않습니까? – Silicomancer

+0

관리자가 그런 식으로 좋아하기 때문에. – lpapp

1

안정적으로 나는 다음과 같은 방법을 사용 스레드를 통해 QSignalSpy 작업을하기 위해 : 나는 작업자 스레드에 스파이를 이동 갖는은 변화가 합병되면서이 Qt를 5.4 고정 될 것이라고 말했다 다음과 같이 대기 함수를 다시 구현합니다.

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