假如這里有2個人,1個人寫Qobject的類,一個人寫主執行緒UI。好,我第一個人封裝了一個Obj,他的建構式是這樣的:
ClassA::ClassA(QObject *parent) : QObject(parent)
{
ti = new QTimer(this);
ti->setInterval(1000);
connect(ti, SIGNAL(timeout()), this, SLOT(onTimeut()));
ti->start();
}
他覺得我自己的timer就是定時觸發我一個槽函式,而且這個timer是我的,所以把timer的parent指向自己,這樣子自己被析構的時候,會一起把timer也析構掉。解構式都可以懶得寫了,沒問題。
另外一個人寫主執行緒:
ClassA *a = new ClassA();
QThread *th = new QThread();
a->movetoThread(th);
th->start();
這個人不知道這個Class A里實作什么,他也不需要知道,只需要按照語法規則new a,然后后面delete a就對了,但是這樣delete的時候,QTimer就是報錯,QObject::killTimer: timers cannot be stopped from another thread。
哦對了,如果你覺得寫主執行緒的人應該先退出子執行緒,那很可惜,你這么寫一樣報錯。
th->quit();
th->wait();
th->deletelater();
delete a;
那么請問:2個人都覺得自己合情合理,沒有問題,那到底是誰的問題?有什么通用的方法或者思想來避免這種問題。
uj5u.com熱心網友回復:
經過反復的測驗,我發現這樣居然是唯一解?必須要信號槽,不能手動quit wait delete。主要幾個關鍵點:對于ClassA這個類來說,關鍵在于構造的時候new QTimer是傳了個parent指定了ClassA,那么別人把ClassA移到新執行緒時候,timer會跟著一起到新的執行緒里面。那么在delete時候,delete執行的那個執行緒,不用信號槽,大概率是在主執行緒去洗掉,那么這個時候,timer->thread()和currentThread()就不是同一個執行緒,就會報錯。如果先把子執行緒quit wait delete掉,那么timer和ClassA的thread()就是NULL,一樣報錯。
那么能不能在洗掉子執行緒后,把ClassA再拖回主執行緒呢?很可惜,QT說明檔案寫明了,moveToThread只能把Obj“推出去”,不能“拉回來”。那么能不能子執行緒先來一套quit() wait() deletelater(),然后再ClassA->deletelater()呢,也不行,因為ClassA的thread()已經是空了,deletelater實際上是postEvent的,也就是說ClassA是不會處理這個事件的。你們可以試一下,解構式并不會被呼叫,而且這是災難的。
uj5u.com熱心網友回復:
總結一下:1.Obj里的其他Obj,包括QTimer,指定了parent為自己this的話,別人在外面moveToThread會把你的timer的執行緒也移動過去。
2.如果別人在外面delete你的Obj,那么你的Timer析構時候呼叫的stop(),里面判斷thread() != QThread::currentThread()就成立了,然后就報出警告qWarring啦。
3.deletelater是postEvent的,也就是析構會在槽函式,也就是在子執行緒里,這個或許是唯一解了,畢竟你的timer的析構的stop()要在子執行緒干的呢。
4.moveToThread只能把Obj推去子執行緒,不能拉回主執行緒。
5.那就是說,timer的stop時候,timer的thread()要完好無損,不能被刪掉了哦,然后執行stop()的這個執行緒,不能是其他執行緒呢,所以就要信號槽一石二鳥,在th->wait()這個函式里面,會等待,然后就會發送信號,然后timer啊ta啊就會在子執行緒里被析構掉咯。然后執行緒自己也析構掉了。
uj5u.com熱心網友回復:
不用QTimer用timerEvent就不會出現這種情況了吧uj5u.com熱心網友回復:
這個你可以試一下,但并不是在我討論的范圍里,我討論的是我正常使用一個東西,我只認qt和c++的規則,其他什么同事之間呀,網友之間的“自定義規則”全部不認,但我必須在僅有的2種規則下,不允許出錯。就是說,誰都不允許搞特殊,如果出現某個東西搞特殊,那就是嚴重破壞封裝性和設計模式規則。我能用timer為啥非得搞特殊用timerevent。uj5u.com熱心網友回復:
如果一定要說是誰的問題,肯定是第一個人的問題。他沒有考慮到這個類會被裝入到另一個執行緒中運行。所以 new 和 delete 不在同一個執行緒中了uj5u.com熱心網友回復:
我覺得 moveToThread() 這種方法好麻煩,還要連接 started 信號 與槽函式,不如繼承 QThread 單干一件事多好
uj5u.com熱心網友回復:
接5樓,不同執行緒的,不能直接delete對方的obj,只能通過信號槽來實作跨執行緒的deleteuj5u.com熱心網友回復:
嗯?換句話說,假如把一個obj通過move來移動到子執行緒,就必須要用信號槽來delete嗎?uj5u.com熱心網友回復:
那是只能某信號->這個obj的deletelater(),這樣子?但是這里有個問題,不夠完整。假如這個obj的執行緒先被退出了,那么這個obj是不會執行事件的,也就是槽函式不會執行呢轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/10810.html
標籤:Qt
