У меня есть живой объект, реализованный следующим образом.Используется для выполнения длинных задач в фоновом режиме.Основной поток вызывает задачи, посылая сигнал в открытые слоты (т.е. 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 () был поставлен в очередь в цикле exec m_thread и выполнялся им как можно скорее.
Как я мог это сделать?
РЕДАКТИРОВАТЬ : На основе предложенного ответа, вот новый код.Метод 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 () будут поставлены в очередь и обработаны, как только поток будет запущен.При вызове из потока объекта он будет выполнен немедленно (не помещен в очередь).
Обратите внимание, что сигнал start () испускается только при запуске потока.Это означает, что вызов метода doTask (), поставленный в очередь до запуска потока, будет выполнен до того, как будет вызван слот метода start ().По этой причине я удалил его из первоначальной реализации.Таким образом, инициализация объекта должна предпочтительно выполняться в конструкторе.