Является ли `moveToThread (nullptr)` допустимым способом извлечения QObject в целевом потоке из его исходного потока? - PullRequest
4 голосов
/ 10 января 2020

Предположим, принадлежит ли объект obj к QThread T1. В идеале, находясь в функции Qhread T2, obj нельзя «вытянуть» из T1 в T2. Это упоминается в документации moveToThread():

Предупреждение: Эта функция не является поточно-ориентированной; текущий поток должен совпадать с текущим сродством потока. Другими словами, эта функция может только "pu sh" объект из текущего потока в другой поток, она не может "вытянуть" объект из любого произвольного потока в текущий поток. Однако есть одно исключение из этого правила: объекты без привязки к потоку могут быть «вытянуты» к текущему потоку.

Этот ответ балл -3 предполагает, что на самом деле это «l ie -дет». Потому что moveToThread(nullptr) сделает объект подвижным из других потоков.
Это идиоматический c способ без побочных эффектов?

void FunctionRunningInT2 (QObject& obj) // `obj` belongs to thread `T1`
{
  obj.moveToThread(nullptr); // line-1 no event processing for obj!?
  obj.moveToThread(T2);      // line-2 is it OK ???
}

Вопрос о дополнении : Что произойдет, если какой-либо signal будет излучен на obj между строкой-1 и строкой-2?
Перефразировано : В случае obj.disconnect() он не принимает любые сигналы потом. Однако сигналы, ожидающие до disconnect(), все еще обрабатываются. Это верно и для moveToThread(nullptr)? Или он также откажется от ожидающих сигналов?

1 Ответ

2 голосов
/ 15 января 2020

Насколько я понимаю, просто невозможно вызвать moveToThread для объекта, живущего в другом потоке. Даже если аргумент nullptr, вы получите сообщения от Qt:

QObject::moveToThread: Current thread ( ... ) is not the object's thread ( ... )
Cannot move to target thread (0x0)

, и объект не будет перемещен из своего потока.

Безопасный способ перетянуть объект в другой поток - это использовать подключение в очереди, то есть предоставление подвижному объекту слота, например

class Moveable : public QObject
{
    Q_OBJECT
public:
    Moveable() : QObject(nullptr) {}

public slots:
    void moveMe(QThread * destination) { moveToThread(destination); }

Таким образом, можно использовать сигнал в объекте mover , например

class Mover : public QObject
{
    Q_OBJECT
signals:
    void moveIt(QThread *);

, соедините их

connect(&mover, &Mover::moveIt, &moveable, &Moveable::moveMe, Qt::QueuedConnection);

и, где необходимо

mover.moveIt(QThread::currentThread());

или

mover.moveIt(to_whatever_thread);

Если кто-то просто не хочет иметь дело с реализацией сигналов и их соединением, можно смело использовать что-то вроде:

QMetaObject::invokeMethod(&moveable, "moveMe", Qt::QueuedConnection, Q_ARG(QThread*, destination_thread));

, снова используя соединение в очереди, но непосредственно вызывая слот.

О дополнительном вопросе . Как только объект перемещен в поток 0x0, как указано здесь :

, обработка событий для этого объекта или его дочерних элементов не может произойти, так как они больше не связаны с какими-либо thread.

Таким образом, объект также прекратит получать сигналы, даже от другого объекта, который также был перемещен в 0x0.

...