Как Qt::DirectConnection действует при использовании в многопоточной среде?
Хотя Qt::QueuedConnection
или Qt::AutoConnection
(в некоторых случаях) предпочтительнее в многопоточной среде, я задаю этот вопрос для понимания цели.
Если сигнал
MySignal()
испускается в потоке A и слотеMySlot()
принадлежит объекту потока B. Оба соединены черезQt::DirectConnection
, как происходит казнь? т.е. если поток A отправляет сигнал потоку B, в то время как поток B выполняется в середине некоторой функцииfoo()
. Будет ли слотMySlot()
называться сразу послеfoo()
финиширует или будет называться параллельноfoo()
?Есть ли сценарий, когда
Qt::DirectConnection
желательно по сравнению с другими в многопоточном приложении?
2 ответа
Есть ли сценарий, когда
DirectConnection
желательно по сравнению с другими в многопоточном приложении?
Да, если ваша ветка B
выполняется только в одной функции и не имеет цикла событий, тогдаDirectConnection
это единственный выбор, который у вас есть. С помощьюAutoConnection
или QueuedConnection
не будет работать, потому что соответствующее событие вызова слота не будет обработано в B
или где-нибудь еще.
Еще одна причина для DirectConnection
может быть, если ваши параметры не сериализуемы / десериализуемы с использованием системы метаобъектов Qt. Если условия дляQt::DirectConnection
удовлетворены (слот является потокобезопасным), вы можете использовать его вместо этого (опасайтесь последствий - см. следующий текст).
Еще одна вещь, которую вы должны принять во внимание, - это распределение сигнала по нескольким слотам. Если вы используетеDirectConnection
и слот должен ждать мьютекса, другие слоты, которые были подключены после этого, не будут активированы, пока слот не вернется. С помощьюQueuedConnection
в этом случае будет обеспечено неблокирующее распространение сигнала. Затем поток B будет блокироваться (в своем внутреннем обработчике событий qt для события вызова слота) вместо потока A в своем операторе "emit".
Еще одна вещь, которую вы должны принять во внимание, - это порядок вызова слотов. Если вы выдаете несколькоemit
операторы один за другим, а слоты одного и того же объекта вызываются с использованием QueuedConnection
, они вызываются в этом порядке, потому что за ними стоят обычные события вызова слота. Если некоторые из этих слотовDirectConnection
, то они вызываются синхронно в передающем потоке, без гарантии порядка относительно других вызовов слотов в очереди!
Изменить: я думаю, что с QObject::deleteLater тоже есть интересный случай. Рекомендую подключиться к нему с помощьюQt::DirectConnection
. Эта функция является потокобезопасной и отправляет событие последующего удаления в целевой поток объекта. Более того, функция также обрабатывает случай, когда поток объекта не имеет запущенного цикла обработки событий (в этом случае объект удаляется при выходе из его потока). Если бы вы использовалиQt::QueuedConnection
и в целевом потоке нет цикла событий, вы бы создали утечку памяти.
Если поток A отправляет сигнал потоку B, а поток B выполняется в середине некоторой функции foo(). Будет ли слот MySlot() вызываться сразу после завершения foo () или он будет вызываться параллельно с foo()?
К сожалению (и как вы подозреваете) Qt::DirectConnection
именно это и B::MySlot()
будет вызываться в потоке A одновременно с тем, что уже происходит в потоке B - foo()
в этом случае. Таким образом, без какой-либо другой формы синхронизации использованиеQt::DirectConnection
как правило, плохая идея, когда отправитель и получатель могут находиться в разных потоках.
Если вы действительно делаете потребуется понятие синхронного поперечного потока сигналов / слотов вызова, то вы можете посмотреть на Qt::BlockingQueuedConnection