2009-08-01 23 views
5

W mojej aplikacji znajduje się wątek główny i wątek roboczy (QThread).
Z głównego wątku chciałbym wywołać metodę mojego wątku roboczego i uruchomić ją w kontekście wątku.Wywoływanie metod w kontekście QThread

Próbowałem użyć QMetaObject::invokeMethod i dać mu opcję QueuedConnection, ale nie działa.
Próbowałem również emitować sygnały z głównego wątku (który jest podłączony do wątku wątku roboczego), ale także nie powiodło się.

Oto urywek z grubsza co starałem:

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(); 
    } 
}; 

Korzystanie drogę 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(); 
} 

Korzystanie drogę sygnału:

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(); 
} 

Oba sposoby wynikają w głównej identyfikator wątku drukowany w QThreaddoWork.

Ponadto, myślałem o wdrożeniu prostego producenta-konsumenta, ale jeśli to działa, czy istnieje jakikolwiek powód, aby nie robić tego w ten sposób?

Odpowiedz

3

Problem polegał na tym, że odbiornik (QThread) "żyje" w głównym wątku, a zatem pętla zdarzeń głównego wątku jest tym, który wykonuje gniazdo.

z Dokumenty QT:

przypadku połączeń w kolejce, szczelina jest wywoływany, gdy sterowanie powraca do pętli zdarzeń gwintu, do którego należy dany obiekt. Slot jest wykonywany w wątku, w którym znajduje się obiekt odbiorcy.

Rozwiązaniem, które znalazłem do tej pory, było stworzenie obiektu wewnątrz wątku() i użycie jego szczelin. W ten sposób właścicielem odbiorcy jest wątek, a następnie slot jest wywoływany w kontekście wątków.

0

Wygląda na to, że wątek roboczy zakończy się, zanim będzie można wywołać dowolną funkcję lub wysłać do niej sygnał.

+1

wątek roboczy znajduje się w jego pętli zdarzeń z powodu wywołania exec() –

2

Ten przykład pokazuje, jak podzielić klasę Worker, aby działała tak, jak chcesz. Musisz również udostępnić referencję lub wskaźnik do instancji Worker, aby móc połączyć się z tym gniazdem.

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(); 
    } 
}; 
1

Pracownik jest tworzony w głównym wątku, dlatego jego zdarzenia są przetwarzane w głównym wątku. Musisz przenieść pracownika do jego własnych wątku:

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

Teraz Qt wie worker życie w nowym wątku, a w kolejce zdarzeń w tej pętli zdarzeń.

Powiązane problemy