我有一个以下面的方式实现的实时对象.它用于在后台执行长任务.主线程通过向公共槽(即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 );
}
Run Code Online (Sandbox Code Playgroud)
只要doTask()由信号调用,这(应该)就可以正常工作.但是如果主线程直接调用doTask(),那么它将由主线程执行.对于某些任务,我想强制执行活动对象的线程执行,即使直接调用slot方法也是如此.
我可以在doTask()前面添加代码来检查当前线程是否为m_thread,在这种情况下它会执行该方法.如果不是,我希望doTask()向'this'发出一个信号,以便doTask()的调用在m_thread exec循环中排队,并尽快由它执行.
我怎么能这样做?
编辑:根据建议的答案,这是新的代码.doTask方法现在通过live objet的线程委托执行,即使主线程直接调用也是如此.信号调用仍然按预期工作.
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 );
}
Run Code Online (Sandbox Code Playgroud)
这是我在单独的线程中支持异步方法执行的最简单的实现.一旦线程启动,doTask()方法的调用将被排队并处理.从对象线程调用时,它将立即执行(不排队).
请注意,只有在线程启动时才会发出started()信号.这意味着在线程启动之前排队的doTask()方法调用将在调用started()方法槽之前执行.这就是我从初始实现中删除它的原因.因此,对象初始化应该优选地在构造函数中执行.
Cal*_*itt 29
你想打电话QMetaObject::invokeMethod来做这件事.在你的情况下,它看起来像
MyTask *task;
int param;
// ...
// Will automatically change threads, if needed, to execute
// the equivalent of:
// (void)task->doTask( param );
QMetaObject::invokeMethod( task, "doTask", Q_ARG( int, param ) );
Run Code Online (Sandbox Code Playgroud)
小智 5
关于我要添加的唯一改进,是节省了一些查找方法的时间:
class MyTask {
// ...
private:
int m_doTaskImplIndex;
};
MyTask::MyTask() :
//...
m_doTaskImplIndex(metaObject()->indexOfMethod("doTaskImpl"))
//...
{}
void MyTask::doTask( int param )
{
metaObject()->method(m_doTaskImplIndex).invoke(this, Q_ARG( int, param ) );
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
18988 次 |
| 最近记录: |