在我的節目,我是子類的QThread開始了,我實現了虛擬方法run()
像這樣:知道當的QThread的事件循環已經從另一個線程
void ManagerThread::run() {
// do a bunch of stuff,
// create some objects that should be handled by this thread
// connect a few signals/slots on the objects using QueuedConnection
this->exec(); // start event loop
}
現在,在另一個線程(我們稱之爲MainThread
),我開始ManagerThread
和等待它的started()
信號,之後我繼續使用應該由ManagerThread
處理的信號和時隙。然而,started()
信號基本上emmitted run()
被稱爲權之前,讓取決於線程調度我失去了從MainThread
一些信號,因爲事件循環還沒有開始!
(編輯:原來,這不是問題,它只是將信號在時間上不相連,但出於同樣的原因)
我能正確調用exec()
之前發出的信號,但是這也要求爲了麻煩。
是否有任何明確/簡單的方式知道事件循環已經開始?
謝謝!
EDIT2:(液)
好了,所以原來的問題是不正是我措辭。事件循環未開始的事實不是問題,因爲應該排隊,直到它開始。問題是,一些信號會不會被連接的時間,因爲run()
被稱爲前started()
信號被髮射是called-。
解決方案是在所有連接之後並且在exec之前發出另一個自定義信號。這樣所有的信號/插槽都可以確保連接。
這是我的問題的解決方案,但並不真正解決主題標題問題。我已經接受了確實回答題目的答案。
我已經離開我的代碼下面那些好奇,與溶液中,等待在instance()
方法的另一個信號。
CODE:
很多的你是說我不能失去信號,所以這裏是我的整個類的實現。我會簡化它到最基本的必需品。
這裏是接口ManagerThread
:
// singleton class
class ManagerThread: public QThread {
Q_OBJECT
// trivial private constructor/destructor
public:
static ManagerThread* instance();
// called from another thread
public:
void doSomething(QString const& text);
// emitted by doSomething,
// connected to JobHandler whose affinity is this thread.
signals:
void requestSomething(QString const& text);
// reimplemented virtual functions of QThread
public:
void run();
private:
static QMutex s_creationMutex;
static ManagerThread* s_instance;
JobHandler* m_handler; // actually handles the requests
};
一些相關的實現。創建線程的單一實例:
ManagerThread* ManagerThread::instance() {
QMutexLocker locker(&s_creationMutex);
if (!s_instance) {
// start socket manager thread, and wait for it to finish starting
s_instance = new ManagerThread();
// SignalWaiter essentially does what is outlined here:
// http://stackoverflow.com/questions/3052192/waiting-for-a-signal
SignalWaiter waiter(s_instance, SIGNAL(started()));
s_instance->start(QThread::LowPriority);
qDebug() << "Waiting for ManagerThread to start";
waiter.wait();
qDebug() << "Finished waiting for ManagerThread thread to start.";
}
return s_instance;
}
運行重新實現,設置了信號/插槽和啓動事件循環:
void ManagerThread::run() {
// we are now in the ManagerThread thread, so create the handler
m_handler = new JobHandler();
// connect signals/slots
QObject::connect(this,
SIGNAL(requestSomething(QString const&)),
m_handler,
SLOT(handleSomething(QString const&)),
Qt::QueuedConnection);
qDebug() << "Starting Event Loop in ManagerThread";
// SOLUTION: Emit signal here and wait for this one instead of started()
this->exec(); // start event loop
}
功能是委託處理,以正確的線程。這是 我發出對丟失的信號:
void ManagerThread::doSomething(QString const& text) {
qDebug() << "ManagerThread attempting to do something";
// if calling from another thread, have to emit signal
if (QThread::currentThread() != this) {
// I put this sleep here to demonstrate the problem
// If it is removed there is a large chance the event loop
// will not start up in time to handle the subsequent signal
QThread::msleep(2000);
emit(requestSomething(text));
} else {
// just call directly if we are already in the correct thread
m_handler->handleSomething(text);
}
}
最後,這裏是從MainThread
的代碼,如果事件循環沒有及時啓動會失敗:
ManagerThread::instance()->doSomething("BLAM!");
假設處理程序只是打印出它的文本,以下是打印成功運行的內容:
W請等待ManagerThread線程啓動
已完成等待ManagerThread線程啓動。
ManagerThread中啓動事件循環
ManagerThread嘗試做某事
BLAM!
這裏是一個不成功的運行會發生什麼:
等待ManagerThread開始
完畢等待ManagerThread線程啓動。
ManagerThread試圖做一些事情
在ManagerThread
起事件循環很明顯,事件循環開始信號發出了之後,和BLAM從不打印。 這裏有一個競爭條件,需要知道事件循環何時開始, 爲了解決它。
也許我失去了一些東西,問題是不同的東西......
感謝這麼多,如果你真的閱讀所有!唷!
你確定你失去了信號?如果信號從線程內部連接,則它們被設置爲排隊信號。如果它們沒有線程連接,則它們是同步信號。查看該場景的其餘部分以查看信號如何/何時連接會很有幫助。 – lefticus 2011-03-10 15:51:09
@lefticus我已使用所需的代碼更新了我的帖子以查看問題。最後,我包含了兩個程序的輸出。一個成功(事件循環時間創建),另一個失敗(在事件循環創建之前信號丟失)。 – 2011-03-10 18:26:20