1、使用QObject子類的movetothread方法 代替 QThread子類的run 實現多線程。
使用原始QThread對象的start方法啟動線程==>連接原始QThread對象的started信號到QObject子類的槽(線程部分)。
2、有parent的object是不能moveToThread被移動到其他線程中的,所以還需要把子類對象給setParent(NULL)一下再moveToThread。
3、QObject子類對象在movetothread后,不要在線程中進行delete,因為QObject子類對象的內存管理還屬於主線程。
4、QCoreApplication::exec()開啟了主線程的事件循環。子線程也是一樣,需要通過調用exec開啟事件循環,否則事件不會分發給對對象。
QThread線程並不存在exec()函數。原因是exec()函數在QThread的run()中已經調用了。
5、postEvent: 可以給別的線程發送事件。事件會在目的對象所屬的線程中運行。異步接口。
sendEvent: 僅用於同一個線程之間發送事件。目的對象必須與當前線程一樣。同步接口
6、跨線程的事件傳遞可以通過 QCoreApplication::postEvent 和 重載QObject類的customEvent的方法 實現。
--------------------------------------------------------------------------------------------------------------------
1) 用原始的QThread的started信號觸發自定義的slot啟動線程(需要connect這個QThread對象的started信號),
而不是派生QThread的類重載run函數啟動線程。
將一個類派生自QObject,然后實現所有的signal/slot,然后通過調用movetothread函數來使他們執行在新的線程里面,
而不是每次都要重新派生QThread,並且派生QThread的另外一個不好的地方是只有run函數內部的代碼才會執行在新線程里面,
相比起來,派生QObject並使用movetothread函數更具有靈活性。
2) 自定義對象(QObject子類)moveToThread進線程后,事件循環可以完全在此線程中運行。而它的內存管理應該還屬於主線程。
有parent的object是不能moveToThread被移動到其他線程中的,所以還需要把子類對象給setParent(NULL)一下再moveToThread.
如下例子中(MyObject* myObj)被moveToThread進線程(QThread *thread),假如對象(MyObject* myObj)有父親,它不能移動這種關系。
在另一個線程(而不是創建它的那個線程)中delete QObject對象是不安全的。除非你可以保證在同一時刻對象不在處理事件。
可以用QObject::deleteLater(),它會投遞一個DeferredDelete事件,這會被對象線程的事件循環最終選取到。
3)exec的重要性。
主線程開始它的事件循環需要調用QCoreApplication::exec(), 子線程需要用QThread::exec(),功能基本是一樣的,當然qt內部肯定是不同的實現。
假如沒有事件循環運行,事件不會分發給對象。
舉例來說,假如你在一個線程中創建了一個QTimer對象,但從沒有調用過exec(),那么QTimer就不會發射它的timeout()信號.
對deleteLater()也不會工作。(這同樣適用於主線程)。
4) 子線程接收事件
a) 如下例子中,子線程並不存在exec()函數。原因是exec()函數在QThread的run()中調用了。
我們這里並沒有做一個QThread派生類,在run中調用exec()。因為我不推薦怎么干。原因很簡單,並不需要這么干。
進一步說明是:qt提供的QThread已經完全滿足線程創建的需要。為什么還要自己再畫蛇添足呢。
b)本例子真正使用的是QCoreApplication::postEvent,和重載QObject類的customEvent的方法。消息一樣會在(MyObject* myObj)所在的線程處理。
5) 關於QCoreApplication::postEvent和QCoreApplication::sendEvent
postEvent: 可以給別的線程發送事件。事件會在目的對象所屬的線程中運行。這是一個異步接口。 sendEvent: 僅用於同一個線程之間發送事件。目的對象必須與當前線程一樣。這是一個同步接口。假如發送給屬於另一個線程的對象,會報錯:ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread a51f48. Receiver '' (of type 'MyObject') was created in thread a3bf18", file kernel\qcoreapplication.cpp, line 539
代碼片段如下:(完整例子請到轉載地址查看)
const QEvent::Type CustomEvent_Login = ( QEvent::Type )5001; //! 建議用5000以上唯一的標識
void MyObject::customEvent( QEvent *e )
{
if ( e->type() == CustomEvent_Login ) //捕獲消息
{
qDebug() << QString( "[%1]catch the event: %2!" )
.arg( ( qlonglong )QThread::currentThreadId() )
.arg( e->type() );
}
}
int main( int argc, char *argv[] )
{
QCoreApplication a( argc, argv );
qDebug() << "main:" << ( qlonglong )QThread::currentThreadId();
//把業務邏輯對象設置進線程,不要把Qthread放進自己線程,這樣的寫法不建議。
//綁定的時候最好設置QueuedConnection。這樣就允許在myObj線程執行,否則可能會在主線程執行。
//如果希望不要再子線程執行,用DirectConnection。
MyObject *myObj = new MyObject;
QThread *thread = new QThread();
myObj->moveToThread( thread );
thread->start();
QObject::connect( thread, SIGNAL( started() ), myObj, SLOT( OnStartedSlot() ), Qt::QueuedConnection );
//定時器
//MyObject::Started/MyObject::Timeout/都會在同一個子線程調用。
QTimer *timer = new QTimer();
QObject::connect( timer, SIGNAL( timeout() ), myObj, SLOT( OnTimeoutSlot() ), Qt::QueuedConnection );
timer->start( 1000 );
//發送事件
QCoreApplication::postEvent( myObj, new QEvent( CustomEvent_Login ) );
qDebug() << QString( "[%1]send the event: %2!" )
.arg( ( qlonglong )QThread::currentThreadId() )
.arg( CustomEvent_Login );
return a.exec();
}
轉載地址:http://blog.csdn.net/shaochat/article/details/41956707?utm_source=tuicool
http://blog.csdn.net/sonydvd123/article/details/8660624