Непонятное поведение сигналов и слотов в зависимости от типа соединения - PullRequest
0 голосов
/ 30 декабря 2018

У меня есть следующий фрагмент

#include <QObject>
#include <QtConcurrent>

class Foo : public QObject {
Q_OBJECT
public:
    explicit Foo(QObject *parent = nullptr) : QObject(parent) {
        connect(this, &Foo::signal, this, &Foo::slot, ConnectionType);
    }

    void startBlockingMap() {
        qDebug("startBlockingMap");
        slot_counter = 0;
        std::atomic_int signal_counter = 0;
        QtConcurrent::blockingMap(nums, [&](auto &&num) {
            ++signal_counter;
            emit signal();
        });
        qDebug("result: %d signals, %d slots", int(signal_counter), int(slot_counter));
        slot_counter = 0;
    }

public slots:
    void slot() { ++slot_counter; }

signals:
    void signal();

private:
    std::atomic_int slot_counter = 0;
    std::vector<int> nums{1, 2, 5, 8};
};

#include "main.moc"

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);
    Foo *foo = new Foo(&app);
    QTimer::singleShot(10, foo, [foo, &app]() {
        foo->startBlockingMap();
        app.quit();
    });
    return app.exec();
}

Он дает разные результаты в зависимости от того, какой тип соединения передается на connect.

Когда ConnectionType равен Qt::DirectConnection вывод равен

startBlockingMap
result: 4 signals, 4 slots

Что ясно.

Когда ConnectionType равно Qt::QueuedConnection, вывод равен

startBlockingMap
result: 4 signals, 0 slots

Что не соответствует.Я думал, что слоты будут выполнены после завершения startBlockingMap, но они не будут выполнены вообще.Зачем?Что случилось?

Наконец, результаты, когда ConnectionType равен Qt::AutoConnection, являются неожиданными.Я ожидал, что они будут такими же, как для Qt::DirectConnection или Qt::QueuedConnection (, как указано в документации ), но они отличаются:

startBlockingMap
result: 4 signals, x slots

Где x изменяется от 0 до 4в зависимости от ... чего-то.Видимо, есть какая-то гонка данных (?).Я не знаю.

Почему слоты не выполняются с Qt::QueuedConnection?Почему вывод, когда тип соединения Qt::AutoConnection отличается от вывода, когда тип соединения прямой и , когда он находится в очереди?Почему это так случайно?

Редактировать: С помощью этого ответа я вижу, что для выполнения слотов, подключенных через соединение с очередями сразу после blockingMap, цикл события должен быть явно продолжен через вызовqApp->processEvents().

1 Ответ

0 голосов
/ 31 декабря 2018

Что нет.Я думал, что слоты будут выполнены после того, как карты будут закончены, но они не будут выполнены вообще.Зачем?Что случилось?

Слоты выполняются, когда элемент управления возвращается в цикл событий, но здесь функция startBlockingMap вызывается из цикла событий, поэтому слоты выполняются, когда startBlockingMapфункция возвращается и элемент управления возвращается в цикл обработки событий.

Почему вывод, когда тип соединения Qt :: AutoConnection, отличается от вывода, когда тип соединения является прямым и когда он находится в очереди?Почему это так случайно?

Функция blockingMap использует разные потоки для вызова вашей лямбды, иногда поток из пула потоков, иногда поток, который выполняет функцию blockingMap (здесь «основной» поток).Вы можете проверить это, добавив строку qDebug() << this->thread() << ' ' << QThread::currentThread(); в лямбду.Теперь emit slot() иногда выполняется из функции, которая не является владельцем объекта, поэтому сигнал ставится в очередь, иногда из основного потока, являющегося владельцем объекта, поэтому слот выполняется напрямую, и выможно увидеть увеличение в консоли.

...