Qt中的中訊號槽與非同步呼叫
Qt中使用訊號-槽機制處理跨物件之間的呼叫,該機制的好處有:
1. 使得呼叫關係的繫結和解除十分靈活,不必修改類成員函式程式碼
2. 在不暴露更多全域性變數的情況下實現跨名稱空間呼叫
3. 可以多個訊號對應多個槽,也可以訊號之間繫結,對應於GUI中的邏輯很方便
4. 利用Qt::QueuedConnection可以實現非同步呼叫
一般使用
connect(this, SIGNAL(TestSignal()), this, SLOT(TestSlot()), Qt::AutoConnection)
第四個引數一般省略
以下詳細談談第4點:
對於一個多執行緒GUI程式來說,經常遇到的需求是後臺有比較複雜的IO、網路、資料處理邏輯,響應的業務邏輯有多個狀態,並常伴有延時。這種情況下用多執行緒處理比用定時器方便。而一旦使用多執行緒,就涉及到與GUI主執行緒的同步問題。
從開發者的角度,希望使用的是“執行緒透明”的互動機制,即直接跨執行緒修改GUI控制元件屬性;GUI中使用者的輸入事件傳遞到資料處理執行緒中,並在適當時被響應和處理。
我們希望圖形庫提供以上封裝好的方法,不需要開發者手動處理互斥鎖、訊息佇列等。
Qt做到了
在Qt中使用
connect(obj1, SIGNAL(TestSignal()), obj2, SLOT(TestSlot()), Qt::QueuedConnection);
跨越物件非同步呼叫訊號-槽。注意在obj2中必須呼叫訊息迴圈
void processEvents(QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents)
這是因為,Qt非同步訊號槽機制內部基於Event,必須由QObject內建的事件響應函式處理到來的事件,並實際執行槽函式。
Qt中的主要使用以下函式傳送訊息:
//新增訊息到佇列末尾
void postEvent(QObject * receiver, QEvent * event, int priority = Qt::NormalEventPriority)
//新增訊息到佇列開頭
bool QCoreApplication::sendEvent(QObject * receiver, QEvent * event)
可以用來發送Qt預定義事件,比如模擬滑鼠點選。也可以自定義事件,自定義事件對應ID要大於1024。
一般而言,我們自定義事件的目的本質上是為了遠端呼叫,故直接使用非同步訊號槽機制即可。除非需要對於傳遞的資料進行復雜的儲存管理,此時再考慮繼承Event包含對應資料結構。
以下程式碼表明,不呼叫訊息迴圈就無法處理非同步訊號槽
//test.h
class AsynchronizedSlotTest : public QObject
{
Q_OBJECT
public:
AsynchronizedSlotTest();
void runTest();
public slots :
void TestSlot();
signals:
void TestSignal();
};
//test.cpp
AsynchronizedSlotTest::AsynchronizedSlotTest() : QObject()
{
//connect(this, SIGNAL(TestSignal()), this, SLOT(TestSlot()), Qt::AutoConnection);
connect(this, SIGNAL(TestSignal()), this, SLOT(TestSlot()), Qt::QueuedConnection);
}
void AsynchronizedSlotTest::runTest()
{
emit TestSignal();
}
int main()
{
AsynchronizedSlotTest slotTest;
slotTest.runTest();
return 0;
}
將第6行改成第5行就可以,因為此時Qt::DirectConnection直接呼叫不依賴訊息迴圈