我有一个使用以下方式实现的活对象。它用于在后台执行长时间任务。主线程通过向公共槽(即doTask)发送信号来调用任务。这是一个简化的示例(未经测试)。
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 );
}
只要通过信号调用doTask(),就像预期的那样工作。但是如果主线程直接调用doTask(),那么它将由主线程执行。对于某些任务,我想强制在活动对象的线程中执行,即使直接调用槽方法。我可以在doTask()前面添加代码,检查当前线程是否为m_thread,在这种情况下执行该方法。如果不是,我希望doTask()向'this'发出一个信号,以便将doTask()的调用排队在m_thread exec循环中,并尽快由其执行。
我该怎么做?
编辑:根据提议的答案,这是新代码。即使由主线程直接调用,doTask方法现在也会委托执行到活动对象的线程。通过信号调用仍然按预期工作。
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 );
}
这是我能找到的最简单的实现来支持在单独的线程中执行异步方法。 doTask() 方法的调用将被排队并在线程启动时立即处理。当从对象线程调用时,它将立即执行(而不是排队)。请注意,只有在线程启动时才会发出 started() 信号。这意味着在线程启动之前排队的 doTask() 方法调用将在调用 started() 方法槽之前执行。这就是我从最初的实现中删除它的原因。因此,最好在构造函数中执行对象初始化。