Qt 信号槽连接源码解读
在声明信号的时候,Qt 会将信号于 QMetaThod 进行绑定,当emit 一个信号的时候, 会调用一个 QMetaMethod::invoke 函数。
查看源码, 在qmetaobject.h 中看到一个函数:
bool QMetaMethod::invoke(QObject *object,
Qt::ConnectionType connectionType,
QGenericReturnArgument returnValue,
QGenericArgument val0,
QGenericArgument val1,
QGenericArgument val2,
QGenericArgument val3,
QGenericArgument val4,
QGenericArgument val5,
QGenericArgument val6,
QGenericArgument val7,
QGenericArgument val8,
QGenericArgument val9) const
{
...
QObjectPrivate::StaticMetaCallFunction callFunction = mobj->d.static_metacall;
if (connectionType == Qt::DirectConnection) {
if (callFunction) {
callFunction(object, QMetaObject::InvokeMetaMethod, idx_relative, param);
return true;
} else {
return QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, idx_relative + idx_offset, param) < 0;
}
}
else if (connectionType == Qt::QueuedConnection) {
if (returnValue.data()) {
qWarning("QMetaMethod::invoke: Unable to invoke methods with return values in "
"queued connections");
return false;
}
int nargs = 1; // include return type
void **args = (void **) malloc(paramCount * sizeof(void *));
Q_CHECK_PTR(args);
int *types = (int *) malloc(paramCount * sizeof(int));
Q_CHECK_PTR(types);
types[0] = 0; // return type
args[0] = 0;
for (int i = 1; i < paramCount; ++i) {
types[i] = QMetaType::type(typeNames[i]);
if (types[i] == QMetaType::UnknownType && param[i]) {
// Try to register the type and try again before reporting an error.
int index = nargs - 1;
void *argv[] = { &types[i], &index };
QMetaObject::metacall(object, QMetaObject::RegisterMethodArgumentMetaType,
idx_relative + idx_offset, argv);
if (types[i] == -1) {
qWarning("QMetaMethod::invoke: Unable to handle unregistered datatype '%s'",
typeNames[i]);
for (int x = 1; x < i; ++x) {
if (types[x] && args[x])
QMetaType::destroy(types[x], args[x]);
}
free(types);
free(args);
return false;
}
}
if (types[i] != QMetaType::UnknownType) {
args[i] = QMetaType::create(types[i], param[i]);
++nargs;
}
}
QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction,0, -1, nargs, types, args));
}
else { // blocking queued connection
#if QT_CONFIG(thread)
if (currentThread == objectThread) {
qWarning("QMetaMethod::invoke: Dead lock detected in "
"BlockingQueuedConnection: Receiver is %s(%p)", mobj->className(), object);
}
QSemaphore semaphore;
QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction,0, -1, 0, 0, param, &semaphore));
semaphore.acquire();
#endif // QT_CONFIG(thread)
}
}
可以看到当信号槽是Qt::DirectConnection的时候,会直接调用槽函数,
是Qt::QueuedConnection 连接的话,就 压入事件队列 QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction,0, -1, nargs, types, args));
而在 下列函数中实现事件的压缩。
void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority) {
...
//对事件压缩
QMutexUnlocker locker(&data->postEventList.mutex);
// if this is one of the compressible events, do compression
if (receiver->d_func()->postedEvents
&& self && self->compressEvent(event, receiver, &data->postEventList)) {
Q_TRACE(QCoreApplication_postEvent_event_compressed, receiver, event);
return;
}
if (event->type() == QEvent::DeferredDelete)
receiver->d_ptr->deleteLaterCalled = true;
if (event->type() == QEvent::DeferredDelete && data == QThreadData::current()) {
// remember the current running eventloop for DeferredDelete
// events posted in the receiver's thread.
// Events sent by non-Qt event handlers (such as glib) may not
// have the scopeLevel set correctly. The scope level makes sure that
// code like this:
// foo->deleteLater();
// qApp->processEvents(); // without passing QEvent::DeferredDelete
// will not cause "foo" to be deleted before returning to the event loop.
// If the scope level is 0 while loopLevel != 0, we are called from a
// non-conformant code path, and our best guess is that the scope level
// should be 1. (Loop level 0 is special: it means that no event loops
// are running.)
int loopLevel = data->loopLevel;
int scopeLevel = data->scopeLevel;
if (scopeLevel == 0 && loopLevel != 0)
scopeLevel = 1;
static_cast<QDeferredDeleteEvent *>(event)->level = loopLevel + scopeLevel;
}
// delete the event on exceptions to protect against memory leaks till the event is
// properly owned in the postEventList
QScopedPointer<QEvent> eventDeleter(event);
Q_TRACE(QCoreApplication_postEvent_event_posted, receiver, event, event->type());
data->postEventList.addEvent(QPostEvent(receiver, event, priority)); //事件加入队列
eventDeleter.take();
event->posted = true;
++receiver->d_func()->postedEvents;
data->canWait = false;
locker.unlock();
QAbstractEventDispatcher* dispatcher = data->eventDispatcher.loadAcquire();
if (dispatcher)
dispatcher->wakeUp(); //唤醒事件循环
}
...
}
而在 事件分发器的
void QEventDispatcherUNIX::wakeUp()
{
Q_D(QEventDispatcherUNIX);
d->threadPipe.wakeUp(); //唤醒主线程
}
//唤醒QT 事件
void QThreadPipe::wakeUp()
{
if (wakeUps.testAndSetAcquire(0, 1)) {
#ifndef QT_NO_EVENTFD
if (fds[1] == -1) {
// eventfd
eventfd_t value = 1;
int ret;
EINTR_LOOP(ret, eventfd_write(fds[0], value));
return;
}
#endif
char c = 0;
qt_safe_write(fds[1], &c, 1); //使用管道
}
}
在 事件循环中调用事件: