Invoke-slot-Methode ohne Verbindung?
Habe ich ein live-Objekt in der folgenden Weise implementiert. Es wird verwendet, um lange ausführen von Aufgaben im hintergrund. Der Haupt-thread aufrufen, die Aufgaben, indem ein signal an die öffentlichkeit slots (d.h. doTask). Hier ist eine abgespeckte Beispiel (nicht getestet).
class MyTask : public QObject
{
Q_OBJECT
public:
MyTask();
~MyTask();
public slots:
void doTask( int param );
private slots:
void stated();
signals:
void taskCompleted( int result );
private:
QThread m_thread;
};
MyTask::MyTask()
{
moveToThread(&m_thread);
connect( &m_thread, SIGNAL(started()), this, SLOT(started()));
m_thread.start();
}
MyTask::~MyTask()
{
//Gracefull thread termination (queued in exec loop)
if( m_thread.isRunning() )
{
m_thread.quit();
m_thread.wait();
}
}
void MyTask::started()
{
//initialize live object
}
void MyTask::doTask( int param )
{
sleep( 10 );
emit taskCompleted( param*2 );
}
Dieser (sollte) wie erwartet funktionieren, solange doTask() aufgerufen wird, indem ein signal. Aber wenn der Haupt-thread-Aufrufe doTask() direkt wird es dann ausgeführt werden, indem der Haupt-thread. Für einige Aufgaben, die ich erzwingen will eine Hinrichtung durch die live-Objekts thread, auch wenn die slot-Methode direkt aufgerufen wird.
Ich könnte hinzufügen von code vor doTask() prüfen, ob der aktuelle thread ist m_thread in diesem Fall führt es die Methode. Wenn ich nicht möchte, dass doTask() sendet ein signal an 'this', so dass eine Anrufung doTask() in die Warteschlange gestellt, in der m_thread exec-Schleife und ausgeführt, indem Sie es so bald wie möglich.
Wie konnte ich das tun ?
BEARBEITEN: auf der Basis der vorgeschlagenen Antwort, hier ist der neue code. Die doTask Methode delegiert nun die Hinrichtung durch die live-objet-thread, auch wenn der Aufruf direkt durch den Haupt-thread. Aufgerufen durch das signal immer noch wie erwartet funktioniert.
class MyTask : public QObject
{
Q_OBJECT
public:
explicit MyTask( QObject *parent = 0 );
~MyTask();
public slots:
void doTask( int param );
private slots:
void doTaskImpl( int param );
signals:
void taskCompleted( int result );
private:
QThread m_thread;
};
MyTask::MyTask( QObject *parent) : QObject(parent)
{
moveToThread(&m_thread);
m_thread.start();
}
MyTask::~MyTask()
{
//Gracefull thread termination (queued in exec loop)
if( m_thread.isRunning() )
{
m_thread.quit();
m_thread.wait();
}
}
void MyTask::doTask( int param )
{
QMetaObject::invokeMethod( this, "doTaskImpl", Q_ARG( int, param ) );
}
void MyTask::doTaskImpl( int param )
{
//Do the live oject's asynchronous task
sleep( 10 );
emit taskCompleted( param*2 );
}
Dies ist die einfache Implementierung, die ich finden konnte auf die Unterstützung der asynchronen Methode Hinrichtungen in einem separaten thread. Die Aufrufe der doTask () - Methoden werden in die Warteschlange gestellt und verarbeitet, sobald der thread gestartet wird. Beim Aufruf aus dem Objekt-thread, wird es sofort ausgeführt werden (nicht in der Warteschlange).
Beachten Sie, dass die Start () - signal wird nur ausgegeben, wenn der thread gestartet wird. Dies bedeutet, dass doTask() Methode Aufruf in die Warteschlange eingereiht, bevor der thread gestartet wird, ausgeführt wird, bevor die Start () - Methode slot wird aufgerufen. Dies ist der Grund, warum ich es entfernt von der ersten Umsetzung. Objekt-Initialisierung sollten daher vorzugsweise durchgeführt werden, die im Konstruktor.
InformationsquelleAutor der Frage chmike | 2010-07-21
Du musst angemeldet sein, um einen Kommentar abzugeben.
Den Sie anrufen möchten,
QMetaObject::invokeMethod
dies zu tun. In deinem Fall würde es so AussehenInformationsquelleAutor der Antwort Caleb Huitt - cjhuitt
Über die einzige Verbesserung, die ich hinzufügen um etwas Zeit zu sparen auf der Suche bis die Methode:
InformationsquelleAutor der Antwort Kuba Ober
Ich vermute es ist ein bug in MyTask. Wenn ich das verstanden hab Qt-Interna dann richtig
moveToThread(&m_thread);
fehl, wenn
parent
ist nicht 0.InformationsquelleAutor der Antwort Sergey Skoblikov
So, wie etwa wickeln Sie alle in einer Nizza-Klasse?
Ich habe auch noch einen Schlitz
finishPlease
, die Hinzugefügt werden, als letztes element in die Nachricht todo-Liste, und gibt die Rückmeldung an das Hauptprogramm, wenn es tatsächlich verarbeitet alle anstehenden Meldungen, bevor er getötet werden kann.InformationsquelleAutor der Antwort at-2500