一、以前就發現過這個問題:
在Qt項目中,有時候爲了讓自己的類,可以重載操作符 '=','<<','>>'. 也有時候需要用一個類進行文件的讀寫,所以很多C++類還是要簡單化的,不需要繼承QObject,不需要Qt的元對象機制。
但是對於這些簡單C++類,有些時候要是調用Qt的信號槽當做參數進行跨線程發送,就會出現如下問題:
這種情況一般,編譯可以通過,但會出現如下提示。
QOBject::connect:Cannot queue arguments of type 'MoSystemLog'
(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