Qt多線程間訊號槽傳遞非QObject類型對象的參數

來源:互聯網
上載者:User

部分摘自http://www.cnblogs.com/codingmylife/archive/2010/04/30/1725139.html

最近做的項目,需要線程中間發出一個訊號,然後由進程中間的一個槽函數來接收。傳遞的參數是我自己定義的結構體和enum,不知為何發出訊號後,始終不能由槽函數接收。於是到網上搜尋了一下,有了下面的原理。

 

QObject::connect: Cannot queue arguments of type 'ERROR_LEVEL' 
(Make sure 'ERROR_LEVEL' is registered using qRegisterMetaType().)

其中ERROR_LEVEL只是我定義的枚舉類型即enum ERROR_LEVEL。然後在Qt的訊號-槽函數的參數中使用了這個枚舉型,在發送訊號時就出現了上述警告。上面警告的大概意思是訊號隊列中無法使用ERROR_LEVEL類型,要使用qRegisterMetaType()註冊該類型後方可使用。

      通常使用的connect,實際上最後一個參數使用的是Qt::AutoConnection類型:

bool QObject::connect ( const QObject *  sender, const char *  signal, const QObject *  receiver, const char *  method,Qt::ConnectionType  type = Qt::AutoConnection )

Qt支援6種串連方式,其中3中最主要:

  • Qt::DirectConnection(直連方式)

      當訊號發出後,相應的槽函數將立即被調用。emit語句後的代碼將在所有槽函數執行完畢後被執行。(訊號與槽函數關係類似於函數調用,同步執行

  • Qt::QueuedConnection(排隊方式)

      當訊號發出後,排隊到訊號隊列中,需等到接收對象所屬線程的事件迴圈取得控制權時才取得該訊號,調用相應的槽函數。emit語句後的代碼將在發出訊號後立即被執行,無需等待槽函數執行完畢。(此時訊號被塞到訊號隊列裡了,訊號與槽函數關係類似於訊息通訊,非同步執行

  • Qt::AutoConnection(自動方式)

      Qt的預設串連方式,如果訊號的發出和接收這個訊號的對象同屬一個線程,那個工作方式與直連方式相同;否則工作方式與排隊方式相同。

      我的項目中的確跨線程使用了ERROR_LEVEL為參數類型的訊號,因此使用的應當是排隊方式的訊號-槽機制,出現“隊列中無法使用ERROR_LEVEL類型”的警告資訊就可以理解了。放狗搜了一圈,有篇文章提供了個這樣的解決方案:

connect(cm, SIGNAL(sendLog(QUuid, QByteArray, bool)), 
            this,SLOT(sendRes(QUuid,QByteArray,bool))); 
改為: 
connect(cm, SIGNAL(sendLog(QUuid, QByteArray, bool)), 
            this,SLOT(sendRes(QUuid,QByteArray,bool)), Qt::DirectConnection);

這樣做的確能使警告資訊消失,因為Qt官方文檔寫了:

With queued connections, the parameters must be of types that are known to Qt's meta-object system, because Qt needs to copy the arguments to store them in an event behind the scenes.

即使用排隊方式的訊號-槽機制,Qt的元對象系統(meta-object system)必須知道訊號傳遞的參數類型。這裏手動改為直連方式,Qt的元對象系統就不必知道參數類型了,於是警告資訊消失。但這樣做是不安全的,見Qt官方文檔:

Be aware that using direct connections when the sender and receiver live in different threads is unsafe if an event loop is running in the receiver's thread, for the same reason that calling any function on an object living in another thread is unsafe.

 

解決方案有兩種:

一、把自己定義的類型註冊為元群組類型,使用qRegisterMetaType()註冊,可以把這個函數放在connect()函數使用之前。

參考代碼:

1 #include <QMetaType>//記得包含這個標頭檔2 //my_type是我自己定義的類型3 qRegisterMetaType<my_type>("my_type");4 connect(xx,SIGNAL(xx(my_type)),xx,SLOT(xx(my_type)));

二、在connect函數的第五個參數加入Qt::DirectConnection

1 connect(xx,SIGNAL(xx(my_type)),xx,SLOT(xx(my_type)),connect(xx,SIGNAL(xx(my_type)),xx,SLOT(xx(my_type))););

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.