錯誤提示:Error: Cannot create children for a parent that is in a different thread.
錯誤案例分析
新建SerialLink子線程,繼承QThread,並重寫它的run(),調用 start()函數時自動調用重載的run()函數。在主線程中創建SerialLink類的對象。
串口_port在SerialLink的頭文件中定義,在_hardwareConnect()函數中初始化。在_connect()函數中調用start()函數啟動線程,自動調用重載的run()函數。
Class SerialLink: public QThread { …… QSerialPort* _port; …… } void SerialLink:: _hardwareConnect( ) { …… _port = new SerialPort( ); …… } void SerialLink:: _connect( ) { …… _hardwareConnect( ); start( ); …… } void SerialLink:: run( ) { …… }
該錯誤是跨線程調用引起的。
原因:_port的初始化是在SerialLink類中,SerialLink子線程是在主線程中創建的子線程,在SerialLink對象本身工作在主線程下,其中定義的所有東西都屬於創建SerialLink的線程,即主線程,所以_port應該是屬於主線程(父線程)的;只有run()范圍內的代碼工作在次線程中,所以在SerialLink的run()中調用_port屬於跨線程調用,就會出現異常。
解決辦法:將_port在run函數中初始化,_port就是在同一子線程中創建和調用,不會出現跨線程調用錯誤。
void SerialLink* run( ) { _hardwareConnect( ); …… } void SerialLink* _connect( ) { …… start( ); …… } void _hardwareConnect( ) { …… _port = new SerialPort( ); …… }
總結
Thread對象本身工作在主線程下,即使調用其定義的變量和方法,也是工作在主線程下,只有run()范圍內的代碼才工作在子線程中。為避免跨線程調用引起異常,一個對象的創建和調用要放在同一線程中。
推薦的工作方式:利用Qt的事件驅動特性,將需要在次線程中處理的業務放在獨立的模塊(類)中,由主線程創建完該對象后,將其移交給指定的線程,且可以將多個類似的對象移交給同一個線程。
connect連接類型:
1) 自動連接(AutoConnection),默認的連接方式,如果信號與槽,也就是發送者與接受者在同一線程,等同於直接連接;如果發送者與接受者處在不同線程,等同於隊列連接。
2) 直接連接(DirectConnection),當信號發射時,槽函數立即直接調用。無論槽函數所屬對象在哪個線程,槽函數總在發送者所在線程執行。
3) 隊列連接(QueuedConnection),當控制權回到接受者所在線程的事件循環時,槽函數被調用。槽函數在接受者所在線程執行。
在GUI程序中,主線程也叫GUI線程,因為它是唯一被允許執行GUI相關操作的線程。對於一些耗時的操作,如果放在主線程中,就會出現界面無法響應的問題。這種問題的一種解決方式是,把這些耗時操作放到子線程中。