6. Qt 信号与信号槽 (7)-QMetaObject:: activate
生活随笔
收集整理的這篇文章主要介紹了
6. Qt 信号与信号槽 (7)-QMetaObject:: activate
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
最后調用callFunction() 或者metaCall()
void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv) {// 這里得到的是QObject的數據,首先判斷是否為阻塞設置if (sender->d_func()->blockSig)return;// 得到全局鏈表QConnectionList * const list = ::connectionList();if (!list)return;QReadLocker locker(&list->lock);void *empty_argv[] = { 0 };if (qt_signal_spy_callback_set.signal_begin_callback != 0) {locker.unlock();qt_signal_spy_callback_set.signal_begin_callback(sender, from_signal_index,argv ? argv : empty_argv);locker.relock();}// 在sender的哈希表中得到sender的連接QConnectionList::Hash::const_iterator it = list->sendersHash.find(sender);const QConnectionList::Hash::const_iterator end = list->sendersHash.constEnd();if (it == end) {if (qt_signal_spy_callback_set.signal_end_callback != 0) {locker.unlock();qt_signal_spy_callback_set.signal_end_callback(sender, from_signal_index);locker.relock();}return;}QThread * const currentThread = QThread::currentThread();const int currentQThreadId = currentThread ? QThreadData::get(currentThread)->id : -1;// 記錄sender連接的索引QVarLengthArray<int> connections;for (; it != end && it.key() == sender; ++it) {connections.append(it.value());// 打上使用標記,因為可能是放在隊列中list->connections[it.value()].inUse = 1;}for (int i = 0; i < connections.size(); ++i) {const int at = connections.constData()[connections.size() - (i + 1)];QConnectionList * const list = ::connectionList();// 得到連接QConnection &c = list->connections[at];c.inUse = 0;if (!c.receiver || (c.signal < from_signal_index || c.signal > to_signal_index))continue;// 判斷是否放到隊列中// determine if this connection should be sent immediately or// put into the event queueif ((c.type == Qt::AutoConnection&& (currentQThreadId != sender->d_func()->thread|| c.receiver->d_func()->thread != sender->d_func()->thread))|| (c.type == Qt::QueuedConnection)) {::queued_activate(sender, c, argv);continue;}// 為receiver設置當前發送者const int method = c.method;QObject * const previousSender = c.receiver->d_func()->currentSender;c.receiver->d_func()->currentSender = sender;list->lock.unlock();if (qt_signal_spy_callback_set.slot_begin_callback != 0)qt_signal_spy_callback_set.slot_begin_callback(c.receiver, method, argv ? argv : empty_argv); #if defined(QT_NO_EXCEPTIONS)c.receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv); #elsetry {// 調用receiver的方法c.receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);} catch (...) {list->lock.lockForRead();if (c.receiver)c.receiver->d_func()->currentSender = previousSender;throw;} #endifif (qt_signal_spy_callback_set.slot_end_callback != 0)qt_signal_spy_callback_set.slot_end_callback(c.receiver, method);list->lock.lockForRead();if (c.receiver)c.receiver->d_func()->currentSender = previousSender;}if (qt_signal_spy_callback_set.signal_end_callback != 0) {locker.unlock();qt_signal_spy_callback_set.signal_end_callback(sender, from_signal_index);locker.relock();} }void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv) {int signal_index = signalOffset + local_signal_index;/* 我們所做的第一件事,是快速檢查一個 64 位的位蒙版 bit-mask。如果為 0,* 我們就知道沒有連接到該信號的東西,可以迅速返回,* 這意味著,發送一個沒有與槽連接的信號是相當迅速的。*/if (!sender->d_func()->isSignalConnected(signal_index))return; // nothing connected to these signals, and no spy/* ... 跳過調試信息和 QML 調用,以及一些合理性檢查 ... *//* 使用互斥鎖,因為 connectionList 中的所有操作都是線程安全的 */QMutexLocker locker(signalSlotLock(sender));/* 獲取該信號的 ConnectionList。此處做了一些簡化。真實的代碼還為列表添加了引用計數和一些合理性檢查 */QObjectConnectionListVector *connectionLists = sender->d_func()->connectionLists;const QObjectPrivate::ConnectionList *list =&connectionLists->at(signal_index);QObjectPrivate::Connection *c = list->first;if (!c) continue;// 我們需要最后一次檢查,確保在信號發出的過程中添加的信號不會在本次發出過程被觸發。QObjectPrivate::Connection *last = list->last;/* 遍歷槽 */do {if (!c->receiver)continue;QObject * const receiver = c->receiver;const bool receiverInSameThread = QThread::currentThreadId() == receiver->d_func()->threadData->threadId;// 確定該連接應該立即發出,還是放入事件隊列if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)|| (c->connectionType == Qt::QueuedConnection)) {/* 從根本上說,就是復制參數,發出事件 */queued_activate(sender, signal_index, c, argv);continue;} else if (c->connectionType == Qt::BlockingQueuedConnection) {/* ... 跳過 ... */continue;}/* 助手結構體,設置 sender()(并且在超出作用域之后重新設回 */QConnectionSenderSwitcher sw;if (receiverInSameThread)sw.switchSender(receiver, sender, signal_index);const QObjectPrivate::StaticMetaCallFunction callFunction = c->callFunction;const int method_relative = c->method_relative;if (c->isSlotObject) {/* ... 跳過 ... Qt5 風格的指向函數指針的連接 */} else if (callFunction && c->method_offset metaObject()->methodOffset()) {/* 如果存在 callFunction(指向由 moc 生成的 qt_static_metacall 的指針,* 調用該函數。還需要檢查已保存的 metodOffset 是否依舊可用* (因為我們可能在析構函數中調用) */locker.unlock(); // 實際調用時不能持有鎖callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv);locker.relock();} else {/* 動態對象 */const int method = method_relative + c->method_offset;locker.unlock();metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv);locker.relock();}// 檢查該對象是否被槽析構if (connectionLists->orphaned) break;} while (c != last && (c = c->nextConnectionList) != 0); }總結
以上是生活随笔為你收集整理的6. Qt 信号与信号槽 (7)-QMetaObject:: activate的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 6. Qt 信号与信号槽 (6)- QO
- 下一篇: Qt 原理-MOC(1)Meta Obj