emit изнутри

После того как мы связали signal и слот через метод connect можно попробовать вызвать сигнал и посмотреть отладчиком как он работает.

Раннее мы примерно поняли как работает connect, см. connect изнутри.

Реализации метода сигнала в файле *.cpp нет, но он реализуется в moc_xxxxx.cpp файле, который нам автоматически генерирует moc препроцессор.

Вот пример одного из реализации сигналов:

// SIGNAL 0
void Class1::sig_foo2(const QVariant & _t1)
{
    void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
    QMetaObject::activate(this, &staticMetaObject, 0, _a);
}

Внутри метода QMetaObject::activate собственно и будет вызываться слот:

QMetaObject::activate
// SIGNAL 0
void Class1::sig_foo2(const QVariant & _t1)
void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
                           void **argv)
{
    int signalOffset;
    int methodOffset;
    computeOffsets(m, &signalOffset, &methodOffset);

    int signal_index = signalOffset + local_signal_index;

    if (!sender->d_func()->isSignalConnected(signal_index))
        return; // nothing connected to these signals, and no spy

    if (sender->d_func()->blockSig)
        return;

    int signal_absolute_index = methodOffset + local_signal_index;

    // формируем список аргументов для слота
 
    void *empty_argv[] = { 0 };
    if (qt_signal_spy_callback_set.signal_begin_callback != 0) {
        qt_signal_spy_callback_set.signal_begin_callback(sender, signal_absolute_index,
                                                         argv ? argv : empty_argv);
    }

   // получили signal_index 

    Qt::HANDLE currentThreadId = QThread::currentThreadId();

    QMutexLocker locker(signalSlotLock(sender));
    QObjectConnectionListVector *connectionLists = sender->d_func()->connectionLists;
    if (!connectionLists) {
        locker.unlock();
        if (qt_signal_spy_callback_set.signal_end_callback != 0)
            qt_signal_spy_callback_set.signal_end_callback(sender, signal_absolute_index);
        return;
    }
    ++connectionLists->inUse;


    const QObjectPrivate::ConnectionList *list;
    if (signal_index < connectionLists->count())
        list = &connectionLists->at(signal_index);
    else
        list = &connectionLists->allsignals;

    do {
        QObjectPrivate::Connection *c = list->first;
        if (!c) continue;
        // We need to check against last here to ensure that signals added
        // during the signal emission are not emitted in this emission.
        QObjectPrivate::Connection *last = list->last;

        do {
            if (!c->receiver)
                continue;

            QObject * const receiver = c->receiver;
            const bool receiverInSameThread = currentThreadId == receiver->d_func()->threadData->threadId;

            // determine if this connection should be sent immediately or
            // put into the event queue
            if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
                || (c->connectionType == Qt::QueuedConnection)) {
                queued_activate(sender, signal_absolute_index, c, argv ? argv : empty_argv);
                continue;
#ifndef QT_NO_THREAD
            } else if (c->connectionType == Qt::BlockingQueuedConnection) {
                locker.unlock();
                if (receiverInSameThread) {
                    qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: "
                    "Sender is %s(%p), receiver is %s(%p)",
                    sender->metaObject()->className(), sender,
                    receiver->metaObject()->className(), receiver);
                }
                // если слот (ресивер) принадлежит другом потоку, то только в очередь ставим и не ждем завершения

                QSemaphore semaphore;
                QCoreApplication::postEvent(receiver, new QMetaCallEvent(c->method_offset, c->method_relative,
                                                                         c->callFunction,
                                                                         sender, signal_absolute_index,
                                                                         0, 0,
                                                                         argv ? argv : empty_argv,
                                                                         &semaphore));
                semaphore.acquire();
                locker.relock();
                continue;
#endif
            }

            QObjectPrivate::Sender currentSender;
            QObjectPrivate::Sender *previousSender = 0;
            if (receiverInSameThread) {
                currentSender.sender = sender;
                currentSender.signal = signal_absolute_index;
                currentSender.ref = 1;
                previousSender = QObjectPrivate::setCurrentSender(receiver, ¤tSender);
            }
            const QObjectPrivate::StaticMetaCallFunction callFunction = c->callFunction;
            const int method_relative = c->method_relative;
            if (callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
                //we compare the vtable to make sure we are not in the destructor of the object.
                locker.unlock();
                if (qt_signal_spy_callback_set.slot_begin_callback != 0)
                    qt_signal_spy_callback_set.slot_begin_callback(receiver, c->method(), argv ? argv : empty_argv);

                // это вызов в текущем потоке

                callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv ? argv : empty_argv);

                if (qt_signal_spy_callback_set.slot_end_callback != 0)
                    qt_signal_spy_callback_set.slot_end_callback(receiver, c->method());
                locker.relock();
            } else {
                const int method = method_relative + c->method_offset;
                locker.unlock();

                if (qt_signal_spy_callback_set.slot_begin_callback != 0) {
                    qt_signal_spy_callback_set.slot_begin_callback(receiver,
                                                                method,
                                                                argv ? argv : empty_argv);
                }

#if defined(QT_NO_EXCEPTIONS)
                metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
#else
                QT_TRY {
                    metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
                } QT_CATCH(...) {
                    locker.relock();
                    if (receiverInSameThread)
                        QObjectPrivate::resetCurrentSender(receiver, ¤tSender, previousSender);

                    --connectionLists->inUse;
                    Q_ASSERT(connectionLists->inUse >= 0);
                    if (connectionLists->orphaned && !connectionLists->inUse)
                        delete connectionLists;
                    QT_RETHROW;
                }
#endif

                if (qt_signal_spy_callback_set.slot_end_callback != 0)
                    qt_signal_spy_callback_set.slot_end_callback(receiver, method);

                locker.relock();
            }

            if (receiverInSameThread)
                QObjectPrivate::resetCurrentSender(receiver, ¤tSender, previousSender);

            if (connectionLists->orphaned)
                break;
        } while (c != last && (c = c->nextConnectionList) != 0);

        if (connectionLists->orphaned)
            break;
    } while (list != &connectionLists->allsignals &&
        //start over for all signals;
        ((list = &connectionLists->allsignals), true));

    --connectionLists->inUse;
    Q_ASSERT(connectionLists->inUse >= 0);
    if (connectionLists->orphaned) {
        if (!connectionLists->inUse)
            delete connectionLists;
    } else if (connectionLists->dirty) {
        sender->d_func()->cleanConnectionLists();
    }

    locker.unlock();

    if (qt_signal_spy_callback_set.signal_end_callback != 0)
        qt_signal_spy_callback_set.signal_end_callback(sender, signal_absolute_index);

}

Работа с одним потоком

Для варианта когда sender и receiver в одном потоке будет вызываться метод callFunction:

сallFunction (для единого потока) это не что иное как вызов:
void Class1::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
    if (_c == QMetaObject::InvokeMetaMethod) {
        Q_ASSERT(staticMetaObject.cast(_o));
        Class1 *_t = static_cast<Class1 *>(_o);
        switch (_id) {
        case 0: _t->sig_foo1(); break;
        case 1: _t->sig_foo2((*reinterpret_cast< const QVariant(*)>(_a[1]))); break;
        case 2: _t->slot1(); break;
        case 3: _t->slot_foo1(); break;
        case 4: _t->slot_foo2((*reinterpret_cast< const QVariant(*)>(_a[1]))); break;
        default: ;
        }
    }
}

То есть происходит банальный вызов функции с номером _id.

Когда sender и receiver принадлежат разным потокам.

Происходит постановка вызова в очередь сообщений потока через postEvent. И  в этом случае мы уже не ждем завершения вызова слота.

Как оказывается все просто и логично. Это к тому, что в общем-то каждый может реализовать такой механизм типа сигнал/слот.