Является ли цикл обработки событий Qt безопасным или атомарным? Как это синхронизируется при работе с `QueuedConnection`?
Предположим 2 QThread
s работают со следующим соотношением:
connect(&Object1OfThread1, &Object1::Signal,
&Object2OfThread2, &Object2::Slot, Qt::QueuedConnection);
Таким образом, когда объект из одного потока генерирует сигнал, вызывается слот другого потока. Как обсуждалось в сигналах Qt (QueuedConnection и DirectConnection), из-за Qt::QueuedConnection
, Signal()
размещен / добавлен в цикл обработки событий Thread2. Когда приходит очередь, Slot()
вызывается.
Вопрос: Является ли сам цикл обработки событий потокобезопасным?
а именно Что делать, если Thread1 и Thread3 одновременно отправляют сигнал в цикл событий Thread2.
2 ответа
В статье, упомянутой в этом комментарии, говорится, что очередь событий защищена мьютексом.
Как работают сигналы и слоты Qt - Часть 3. Соединения в очереди и между потоками
QueuedConnection
опубликует событие в цикле событий для последующей обработки.При публикации события (в
QCoreApplication::postEvent
) событие будет помещено в очередь для каждого потока (QThreadData::postEventList
). Очередь событий защищена мьютексом, поэтому нет условий гонки, когда потоки отправляют события в очередь событий другого потока.Как только событие было добавлено в очередь, и если получатель живет в другом потоке, мы уведомляем диспетчера событий этого потока, вызывая
QAbstractEventDispatcher::wakeUp
, Это разбудит диспетчера, если он спал, ожидая новых событий. Если получатель находится в том же потоке, событие будет обработано позже, поскольку цикл событий повторяется.
Цикл событий Qt является потокобезопасным, но не атомарным.
Поток безопасности
Пока Object2OfThread2
состояние всегда изменяется потоком, связанным с Thread2
, не будет никаких гоночных условий. Максимум один слот будет выполнен в любое время.
валентность
Порядок исполнения слотов регулируется:
- обычное вытеснение потока
- Порядок, в котором были сделаны подключения к этому слоту.
- Другие слоты подключены к сигналу.
Поэтому я бы не советовал принимать конкретный порядок выполнения для данного слота.
Что делать, если Thread1 и Thread3 одновременно отправляют сигнал в цикл событий Thread2
- Во-первых, это разные сигналы: два потока не могут излучать один и тот же сигнал одного и того же объекта, так как этот объект находится только в одном объекте QObject.
- Сигнал, подключенный первым, побеждает, при условии, что эти сигналы подключены только к
Object2OfThread2
даже если они "размещены" одновременно. - Например, если сигналы Thread1 подключены к другим сигналам \ слотам, и эти подключения выполняются раньше
Object2OfThread2, &Object2::Slot
они будут обработаны перед публикацией наObject2OfThread2
цикл событий. Если сигналы испускаются одновременно, сигнал Thread3 будет первым в очереди, поэтому первым будет выполняться.