Domanda

Nella mia applicazione c'è il thread principale e un thread di lavoro ( QThread ).
Dal thread principale mi piacerebbe invocare un metodo del mio thread di lavoro e farlo funzionare nel contesto del thread.

Ho provato a usare QMetaObject :: invokeMethod e gli ho dato l'opzione QueuedConnection ma non funziona.
Ho anche provato a emettere segnali dal thread principale (che è collegato allo slot del thread di lavoro) ma anche questo non è riuscito.

Ecco un frammento di circa quello che ho provato:

class Worker : public QThread
{
    Q_OBJECT

public:
    Worker() { }

    void run() 
    { 
        qDebug() << "new thread id " << QThread::currentThreadId(); 
        exec(); 
    }

public slots:
    void doWork()
    {
        qDebug() << "executing thread id - " << QThread::currentThreadId();
    }
};

Utilizzando il modo QMetaObject:

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    qDebug() << "main thread id - " << QThread::currentThreadId();

    Worker worker;
    worker.start();

    QMetaObject::invokeMethod(&worker, "doWork", Qt::QueuedConnection);

    return a.exec();
}

Uso del segnale:

class Dummy : public QObject
{
    Q_OBJECT

public:
    Dummy() { }

public slots:
    void askWork() { emit work(); }

signals:
    void work();
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    qDebug() << "main thread id - " << QThread::currentThreadId();

    Worker worker;
    worker.start();

    Dummy dummy;
    QObject::connect(&dummy, SIGNAL(work()), &worker, SLOT(doWork()), Qt::QueuedConnection);

    QTimer::singleShot(1000, &dummy, SLOT(askWork()));

    return a.exec();
}

In entrambi i modi, l'ID del thread principale viene stampato nel QThread doWork .

Inoltre, ho pensato di implementare un semplice produttore-consumatore, ma se funziona, c'è qualche motivo per non farlo in questo modo?

È stato utile?

Soluzione

Il problema era che il ricevitore (il QThread) 'vive' nel thread principale e quindi il loop degli eventi del thread principale è quello che esegue lo slot.

dai documenti di Qt:

  

Con le connessioni in coda, lo slot viene richiamato quando il controllo ritorna al loop degli eventi del thread a cui appartiene l'oggetto. Lo slot viene eseguito nel thread in cui vive l'oggetto ricevitore.

Quindi la soluzione che ho trovato finora è stata quella di creare un oggetto all'interno del thread run () e utilizzare invece i suoi slot. In questo modo il proprietario del destinatario è il thread e quindi lo slot viene chiamato nel contesto dei thread.

Altri suggerimenti

Questo esempio mostra come puoi dividere la classe Worker per farla funzionare come desideri. È inoltre necessario rendere disponibile un riferimento o un puntatore all'istanza Worker per poter connettersi allo slot.

class Worker : public QObject
{
    Q_OBJECT

public:
    Worker() { }

public slots:
    void doWork()
    {
        qDebug() << "executing thread id - " << QThread::currentThreadId();
    }
};

class WorkerThread : public QThread
{
    Q_OBJECT

public:
    void run()
    {
        qDebug() << "new thread id " << QThread::currentThreadId(); 
        Worker worker;
        exec();
    }
};

Per un semplice esempio produttore-consumatore, dai un'occhiata al blog di Bradley T. Hughes Calpestare senza il mal di testa .

Il lavoratore viene creato nel thread principale, e quindi i suoi eventi vengono elaborati nel thread principale. È necessario spostare il lavoratore nel proprio thread:

Worker worker;
worker.moveToThread(&worker);
worker.start();

Ora Qt conosce worker che vive nel nuovo thread e metterà in coda gli eventi in quel ciclo di eventi.

Sembra che il tuo thread di lavoro sia completo prima che tu possa persino invocare qualsiasi funzione o inviargli un segnale.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top