Я создал свой собственный TestService
который работает на отдельном QThread
, но когда MainLoop
завершает QThread::finished
сигнал не излучается. Я видел похожий вопрос, но проблема была немного другой, потому что ОП была перегрузка QThread
тогда как я просто перемещаю свой класс в поток.
Обратите внимание, что Я не перегружаю QThread
класс я только перегружаю QObject
на основе этого примера: http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
Вот мой TestService
учебный класс:
#include <QObject>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <iostream>
using namespace std;
class TestService: public QObject
{
Q_OBJECT;
private:
volatile int _count;
QWaitCondition _monitor;
QMutex _mutex;
QThread* _thread;
public:
TestService(int numSeconds)
{
_count = numSeconds;
_thread = NULL;
cout << "TestService()" << endl;
}
virtual ~TestService()
{
cout << "~TestService()" << endl;
}
void Start()
{
QMutexLocker locker(&_mutex);
if(_thread == NULL)
{
_thread = new QThread;
// Move this service to a new thread
this->moveToThread(_thread);
// The main loop will be executed when the thread
// signals that it has started.
connect(_thread, SIGNAL(started()), this, SLOT(MainLoop()));
// Make sure that we notify ourselves when the thread
// is finished in order to correctly clean-up the thread.
connect(_thread, SIGNAL(finished()), this, SLOT(OnFinished()));
// The thread will quit when the sercives
// signals that it's finished.
connect(this, SIGNAL(Finished()), _thread, SLOT(quit()));
// The thread will be scheduled for deletion when the
// service signals that it's finished
connect(this, SIGNAL(Finished()), _thread, SLOT(deleteLater()));
// Start the thread
_thread->start();
}
}
void Stop()
{
_count = 0;
_monitor.wakeAll();
}
private slots:
void MainLoop()
{
cout << "MainLoop() Entered" << endl;
while(_count > 0)
{
cout << "T minus " << _count << " seconds." << endl;
QMutexLocker locker(&_mutex);
_monitor.wait(&_mutex, 1000);
_count--;
}
cout << "MainLoop() Finished" << endl;
emit Finished();
}
virtual void OnFinished()
{
cout << "OnFinished()" << endl;
}
signals:
void Finished();
};
Вот код тестирования:
void ServiceTest()
{
cout << "Press q to quit." << endl;
cout << "Press s to start." << endl;
cout << "Press t to stop." << endl;
QSharedPointer<TestService> testService(new TestService(10));
char in = 'a';
while( in != 'q' )
{
switch(tolower(in))
{
case 's':
testService->Start();
break;
case 't':
testService->Stop();
break;
default:
break;
}
cin.get(in);
in = tolower(in);
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
ServiceTest();
QTimer::singleShot(0, &a, SLOT(quit()));
return a.exec();
}
Выход:
Press q to quit.
Press s to start.
Press t to stop.
TestService()
s
MainLoop() Entered
T minus 10 seconds.
T minus 9 seconds.
T minus 8 seconds.
t
MainLoop() Finished
q
~TestService()
Press any key to continue . . .
Кто-нибудь может объяснить, почему finished
не выбрасывается, как я могу это исправить?
Сигнал выполнено () получает излучение от причины, но вы его не улавливаете.
Вот:
connect(_thread, SIGNAL(finished()), this, SLOT(OnFinished()));
Qt::QueuedConnection
используется, как _thread
а также this
(сервис) находятся в разных темах.
Тем временем finished()
испускается, _thread
цикл обработки событий уже завершен, поэтому сигнал не будет доставлен в слот.
Вы можете явно использовать Qt::DirectConnection
,
РЕДАКТИРОВАТЬ:
QTherad работает так:
QThread::start()
{
emit started();
run();
emit finished();
}
QThread::run()
{
eventloop->exec();
}
Итак, к тому времени finished
испускается, Eventloop уже остановить выполнение. И как вы двигаетесь service
в _thread
, цикл событий сервиса _thread
цикл событий.
Обратите внимание, что QObject
Сам по себе не имеет своего собственного цикла событий. Циклы событий создаются диалогами, потоками и приложениями.
На самом деле я буду рекомендовать в вашем простом случае просто использовать QtConcurent::run
, поскольку вы не выполняете фактическую обработку событий в новом потоке, а просто запускаете одну функцию.
Других решений пока нет …