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

 

 
  

  

 

一、以前就發現過這個問題:

在Qt項目中,有時候爲了讓自己的類,可以重載操作符 '=','<<','>>'. 也有時候需要用一個類進行文件的讀寫,所以很多C++類還是要簡單化的,不需要繼承QObject,不需要Qt的元對象機制。


但是對於這些簡單C++類,有些時候要是調用Qt的信號槽當做參數進行跨線程發送,就會出現如下問題:

這種情況一般,編譯可以通過,但會出現如下提示。

 

 

Cpp代碼  收藏代碼

  1. QOBject::connect:Cannot queue arguments of type 'MoSystemLog'  

  2. (Make sure 'MoSystemLog' is registed using qRegisterMetaType().)  

 

意思是說,信號槽隊列中的數據類型必須是系統能識別的元類型,不然得用qRegisterMetaType()進行註冊。

 

二、解決方法:


第一種註冊法:qRegisterMetatType<MoSystemLog>("MoSystemLog")

第二種修改Connect,加一個屬性Qt::directConnection.

connect(cm, SIGNAL(sendLog(QUuid, QByteArray, bool)),

 this,SLOT(sendRes(QUuid,QByteArray,bool)), Qt::DirectConnection);

 

 

三、方法解釋:

 

1、第一種解決方法,即使用排隊方式的信號-槽機制,Qt的元對象系統(meta-object system)必須知道信號傳遞的參數類型。這樣元系統可以將信號參數COPY下來,放在隊列中等待事件喚醒,供槽函數調用。Just a note here, if you would have to pass custom data types between threads in Qt. As we know, a signal-slot connection is then (by default) of type Qt::QueuedConnection. Because in such a situation Qt needs to store passed parameters for a while, it creates their temporary copies. If it doesn’t recognize the passed data type, throws out an error:

2、第二種方法,直接調用對方槽函數,不需要保存參數。但是官方認爲這樣做有風險。

 

 

四、背景知識:

1、首先要了解enum Qt::ConnectionType

 

Qt支持6種連接方式,其中3種最主要:

Qt::DirectConnection(直連方式)

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

Qt::QueuedConnection(排隊方式)

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

Qt::AutoConnection(自動方式)

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

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. If you try to use a queued connection and get the error message

QObject::connect: Cannot queue arguments of type 'MyType'

callqRegisterMetaType() to register the data type before you establish the connection.

注意上面紫色的內容。


connect的第五個參數用於指定反應速度:
若將:
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);

可解決因信號沒有及時發送,致使connect的接收方的槽不能作進一步處理,但是有風險

 

 

參考文章:

1、http://blog.ayoy.net/2009/2/15/registering-custom-types

2、http://dev.wo.com.cn/bbs/redirect.jsp?fid=25127&tid=150302&goto=nextoldset

3、http://blog.csdn.net/s04023083/article/details/4746544


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章