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

Schreibe einen Kommentar