Invoquer la fente de la méthode sans connexion?

J'ai un objet live en œuvre de la manière suivante. Il est utilisé pour exécuter les longues tâches en arrière-plan. Le thread principal invoquer les tâches par l'envoi d'un signal au public slots (c'est à dire doTask). Voici une dépouillé exemple (non testé).

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

Cela devrait fonctionner comme prévu en tant que doTask() est invoquée par un signal. Mais si le thread principal appels doTask() directement, il sera ensuite exécuté par le thread principal. Pour certaines tâches, je veux appliquer une exécution en direct de l'objet thread, même si la fente méthode est appelée directement.

Je pourrais ajouter du code en face de doTask() pour vérifier si le thread courant est m_thread, auquel cas, il exécute la méthode. Si non je voudrais que doTask() émet un signal 'ce' de sorte que l'invocation de la doTask() est en attente dans le m_thread exec boucle et exécuté par elle dès que possible.

Comment pourrais-je le faire ?

MODIFIER: sur la Base des propositions de réponse, voici le nouveau code. Le doTask méthode maintenant les délégués de l'exécution par le live objet thread, même si elle est appelée directement par le thread principal. Appelé par le signal fonctionne toujours comme prévu.

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

C'est le plus simple de mise en œuvre que j'ai pu trouver à l'appui de méthode asynchrone exécutions dans un thread séparé. Les invocations du doTask() les méthodes mises en file d'attente et traitées dès que le thread est démarré. Lorsqu'il est appelé à partir de l'objet thread, il sera exécuté immédiatement (pas de file d'attente).

Noter que le démarrage (le) du signal est émis uniquement lorsque le thread est démarré. Cela signifie que doTask() la méthode d'invocation en file d'attente avant que le thread est démarré exécutera avant de le commencer() la méthode la fente est invoquée. C'est la raison je l'ai enlevé de la mise en œuvre initiale. L'initialisation de l'objet doit donc de préférence être effectuée dans le constructeur.

Je vois un problème ici: les docs disent que vous ne pouvez pas déplacer un objet à un autre thread si elle a un parent. Est-ce que votre code fonctionne si MyTask est créé avec un parent?
Une question similaire a déjà répondu dans QT + Comment appeler la fente de la coutume de code C++ qui s'exécute dans un thread.

OriginalL'auteur chmike | 2010-07-21