I have discovered that even a simple wait on QMutex will cause assertion. What am I possibly doing wrong?
QMutex mutex;
SyncMgr::SyncMgr(QObject *parent) : QObject(parent)
{
moveToThread( &thread );
thread.start();
process = new QProcess( this);
connect( process, SIGNAL(readyReadStandardOutput()), this, SLOT(onReadyReadStandardOutput() ) );
connect( process, SIGNAL(readyReadStandardError()), this, SLOT(onReadyReadStandardError() ) );
}
SyncMgr::~SyncMgr()
{
delete process;
}
void SyncMgr::onConnected()
{
cmdDispatcher.sendGetSerialNo();
// this asserts
waitForResponse.wait( &mutex ); // waitForResponse is CWaitCondition object
// ...
}
I get assert and the error message is:
ASSERT:'copy' in the thread\qmutex.cpp, line 525
You need to lock the mutex before calling waitForResponse.wait().
The SyncMgr::onConnected() method should look like this:
void SyncMgr::onConnected()
{
cmdDispatcher.sendGetSerialNo();
mutex.lock();
waitForResponse.wait( &mutex );
// do something
mutex.unlock();
...
}
You can find more information here:
http://doc.qt.io/qt-5/qwaitcondition.html#wait
Related
I have my main thread which is in charge with the GUI and my worker thread which is in charge with doing stuff with my webcam.
I am able to emit a signal from my main thread to my webcam thread, but it never receives it! Could somebody explain me why?
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
setThreadsAndObj();
setConnects();
startCamera();
}
void MainWindow::setThreadsAndObj()
{
cameraClassPtr = new cameraClass();
cameraThread = new QThread();
}
void MainWindow::setConnects()
{
....
connect(this, &MainWindow::savePicture, cameraClassPtr, &cameraClass::takePicture);
}
void MainWindow::startCamera()
{
//camera start
connect( cameraThread, &QThread::started, cameraClassPtr, &cameraClass::getVideoFrame );
connect( cameraThread, &QThread::finished, cameraClassPtr, &QThread::deleteLater );
connect( cameraThread, &QThread::finished, cameraThread, &QThread::deleteLater );
//receive camera frames
connect(cameraClassPtr, &cameraClass::videoFrameToGui, this, &MainWindow::updateCameraStream);
//start threads
cameraClassPtr->moveToThread(cameraThread);
cameraThread->start();
}
void MainWindow::foo()
{
emit savePicture();
}
void cameraClass::takePicture()
{
qDebug()<<"camera class received signal"; //THIS NEVER GETS PRINTED
}
Could someone explain me why my signal is never received and "camera class received signal" is never printed and how to solve this?
I had this loop in my worker thread:
...
static cv::VideoCapture cap(-1);
if( !cap.isOpened() )
{
qDebug()<< "Could not initialize capturing...\n";
}
qDebug()<<"starting live camera";
cap.set(CV_CAP_PROP_FRAME_WIDTH,240);
cap.set(CV_CAP_PROP_FRAME_HEIGHT,320);
while(1)
{
cap >> imgFrame;
int fd = open("/home/John/Desktop/mainImglock.txt", O_RDWR |O_CREAT, 0666);
int rc = flock(fd, LOCK_EX | LOCK_NB);
if(rc==0)
{
cv::imwrite("/home/John/Desktop/camera.jpg", imgFrame);
}
flock(fd, LOCK_UN);
close(fd);
}
I solved the issue by adding: QApplication::processEvents(); in the while(1) loop, so that the event loop isn't hanging.
You need to subclass QThread and call QThread::exec(); in order to process events in this thread.
I am trying to write thread poll with QThread.
class ThreadPool: public QObject
{
Q_OBJECT
public:
ThreadPool(int maxThreads);
void addTask(MyTask *task);
private:
int maxThreads;
QMutex mutex;
QVector<QPair<bool, QThread>> threads;
QThread *getFreeThread();
public slots:
void freeThread();
};
void ThreadPool::addTask(MyTask* task)
{
QThread *thread = getFreeThread();
task->moveToThread(thread);
connect(thread, SIGNAL(started()), task, SLOT(doWork()));
connect(task, SIGNAL(workFinished()), thread, SLOT(quit()));
connect(thread, SIGNAL(finished()), task, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), this, SLOT(freeThread()));
thread->start();
}
I am creating a limited number of threads in which I want to perform tasks.
However, I do not understand how to get the number of the freed thread.
I know about QThreadPool and Qtconcurrent, but I dont want to use it.
Perhaps, it is worth noting at each thread in QPair's vector is it free or not.
you do not really need a QVector<QPair<bool, QThread>> to keep track of all the threads in your Pool, instead use a QList< QThread* > which holds only the pointers to the free threads.
private:
QList<QThread*> freeThreads; // only free threads
QList<QThread*> allThreads; // just to count the number of all threads
In the slot freeThread() use the sender() method from QObject to get the pointer of the signal sender, which in this case will be the QThread, that has become free
void ThreadPool::freeThread()
{
// get the pointer to the thread that sent the signal:
QObject* threadFreed = QObject::sender();
if( ! freeThreads.contains( threadFreed ) )
{
// save the thread pointer in list
freeThreads << threadFreed;
}
}
Finally getFreeThread() can look like this:
QThread* getFreeThread()
{
if( ! freeThreads.isEmpty() )
{
// take the first free thread
return freeThreads.takeFirst();
}
else
{
if(allThreads.size() < maxThreads )
{
// create a new thread
QThread* thread = new QThread(this);
allThreads << thread;
return thread;
}
else
{
// Maximum number of threads exceeded
// and no free thread is available
return NULL;
}
}
}
Also you should handle the case when a NULL pointer is returned in addTask:
void ThreadPool::addTask(MyTask* task)
{
QThread *thread = getFreeThread();
if( ! thread )
{
// do something else
return;
}
// proceed with thread execution ...
}
I am trying to determine if you can move one object instance to different threads at different points during run-time.
Below is some sample code to show you what I mean:
this->thread1 = new QThread( this );
this->thread2 = new QThread( this );
this->pObject->moveToThread( this->thread1 );
connect(this->thread1, SIGNAL(started()), this->pObject, SLOT(fnc1()));
connect(this->thread2, SIGNAL(started()), this->pObject, SLOT(fnc2()));
this->thread1->start();
//after thread1 has finished
this->pObject->moveToThread( this->thread2 );
this->thread2->start();
Is it possible to do this?
Edit: After Kuba's advice on not using a direct connection and him pointing out I must be interfering with the event loop somehow, I realised manually terminating the threads was not a good idea. I am adding my termination of the threads here to show where I am going wrong and to try and find a better way of achieving the same result.
connect(this->pObject, SIGNAL(finished()), this, SLOT(stopThread()));
void Class::stopThread( void )
{
if( this->thread1->isRunning() )
{
this->thread1->terminate();
return;
}
if( this->thread2->isRunning() )
{
this->thread2->terminate();
this->pObject->moveToThread( this->thread1 );
}
}
void Object::fnc1( void )
{
/*Does some work..*/
finished(); //Calls 'finished' to signal stopThread when done (not stopping on its own)
}
ADDITIONAL INFO
I have MainClass which holds the instances to both thread1, thread2 and pObject (pointer to the object I am trying to move from thread1 to thread2 and back again if necessary).
Main class constructor:
MainClass::MainClass( QWidget *parent ) : QMainWindow(parent)
{
this->ui.setupUi(this);
this->thread1 = new QThread( this );
this->thread2 = new QThread( this );
this->pObject->moveToThread( this->thread1 );
connect( this->pObject, SIGNAL(finished()), this, SLOT(stopThread()) );
connect( this->thread1, SIGNAL(started()), this->pObject, SLOT(fnc1()) );
connect( this->thread2, SIGNAL(started()), this->pObject, SLOT(fnc2()) );
}
Slot for when menu item is clicked:
void MainClass::on_action_call_fnc1_triggered( void )
{
if( this->thread1->isRunning() )
return;
/*EXECUTES SOME CLASSIFIED CODE THAT CANNOT BE SHOWN*/
this->thread1->start();//should trigger fnc1 execution
}
fnc1 held in Object class that is called when thread1 starts:
void Object::fnc1( void )
{
/*DOES SOME MORE SECRET PROCESSING THAT CANNOT BE SHOWN*/
this->finished(); // triggers MainClass::stopThread( void )
}
Slot for when menu item is clicked to start fnc2 executing:
void MainClass::on_action_call_fnc2_triggered( void )
{
if( this->thread1->isRunning() || this->thread2->isRunning() )
return;
this->pObject->moveToThread( this->thread2 );
this->thread2->start();//should trigger fnc2 execution
}
fnc2 held in Object:
void Object::fnc2( void )
{
/*DOES SOME MORE SECRET PROCESSING THAT CANNOT BE SHOWN*/
this->finished(); // triggers MainClass::stopThread( void )
}
stopThread function:
void MainClass::stopThread( void )
{
if( this->thread1->isRunning() )
{
/*this->thread1->quit();
this->thread1->exit();*/
this->thread1->terminate();
//this->thread1->wait( 0 ); //Trying different ways of stopping the thread
return;
}
if( this->thread2->isRunning() )
{
this->thread2->terminate();
//this->thread2->quit(); // Trying different ways of stopping the thread
//this->thread2->exit();
this->pObject->moveToThread( this->thread1 );
}
}
It will work, but you have to assert that the object's thread is indeed finished:
Q_ASSERT(pObject->thread() == nullptr);
pObject->moveToThread(thread2);
When thread1 is finished, the object's thread becomes null and only then you're allowed to move it to another thread from arbitrary thread. Otherwise, if object's thread is not finished yet, you could only move the object from its thread:
QTimer::singleShot(0, pObject, [this]{ pObject->moveToThread(thread2); }
I have some problems with threading inside QT.
#include <QCoreApplication>
#include "handler.hpp"
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
Handler* handler = new Handler();
handler->StartThread();
return a.exec();
}
What I expect is that with handler->StartThread() statement the function within my thread start to write debug messages and once the internal timer within handler finishes I get the nice line [Press ...] and then a return code of 0. However this is not happening. What I get is:
I WORK... ( 0x1540 )
Worker has finished. ( 0x6f4 )
I WORK... ( 0x1540 )
Worker has finished. ( 0x6f4 )
I WORK... ( 0x1540 )
Worker has finished. ( 0x6f4 )
I WORK... ( 0x1540 )
Worker has finished. ( 0x6f4 )
Thread stopped.
And of course when I stop the execution of the application, the return code is: -1073741510. Obviously not that nice of a zero.
Anyway here's the rest of the application code:
Handler.hpp
#ifndef HANDLER_HPP
#define HANDLER_HPP
#include <QObject>
#include <QThread>
#include <QDebug>
#include <QTimer>
#include "testclass.hpp"
class Handler : public QObject
{
Q_OBJECT
public:
Handler();
~Handler();
void StartThread();
public slots:
void functionFinished();
void threadTerminated();
private:
QTimer* shutdown;
QTimer* timer;
QThread* thread;
MyClass* worker;
};
#endif // HANDLER_HPP
Handler.cpp
#include "handler.hpp"
Handler::Handler() {
shutdown = new QTimer();
thread = new QThread();
timer = new QTimer();
worker = new MyClass();
worker->moveToThread(thread);
QObject::connect(thread, SIGNAL(started()), worker, SLOT(runAgain()));
QObject::connect(timer, SIGNAL(timeout()), worker, SLOT(runAgain()));
QObject::connect(worker, SIGNAL(iFinished()), this, SLOT(functionFinished()));
QObject::connect(shutdown, SIGNAL(timeout()), thread, SLOT(quit()));
QObject::connect(thread, SIGNAL(finished()), this, SLOT(threadTerminated()));
shutdown->start(20000);
}
Handler::~Handler() {
QObject::disconnect(thread, SIGNAL(started()), worker, SLOT(runAgain()));
QObject::disconnect(timer, SIGNAL(timeout()), worker, SLOT(runAgain()));
QObject::disconnect(worker, SIGNAL(iFinished()), this, SLOT(functionFinished()));
QObject::disconnect(shutdown, SIGNAL(timeout()), thread, SLOT(quit()));
QObject::disconnect(thread, SIGNAL(finished()), this, SLOT(threadTerminated()));
if (shutdown != 0) {
delete shutdown;
shutdown = 0;
}
if (timer != 0) {
delete timer;
timer = 0;
}
if (thread != 0) {
delete thread;
thread = 0;
}
if (worker != 0) {
delete worker;
worker = 0;
}
}
void Handler::functionFinished() {
qDebug() << "Worker has finished. (" << QThread::currentThreadId() << ")";
timer->start(5000);
}
void Handler::threadTerminated() {
qDebug() << "Thread stopped.";
}
void Handler::StartThread() {
thread->start();
}
MyClass (header - testclass.hpp)
#ifndef TESTCLASS_HPP
#define TESTCLASS_HPP
#include <QTimer>
#include <QObject>
class MyClass : public QObject
{
Q_OBJECT
public:
MyClass();
public slots:
void runAgain();
signals:
void iFinished();
private:
void doWork();
};
#endif // TESTCLASS_HPP
MyClass Source - testclass.cpp
#include "testclass.hpp"
#include <QThread>
#include <QDebug>
MyClass::MyClass() {
}
void MyClass::runAgain() {
doWork();
}
void MyClass::doWork() {
qDebug() << "I WORK...\t(" << QThread::currentThreadId() << ")";
emit iFinished();
}
I've previosly read that it's not a good idea to inherit the classes to be ran inside a thread directly from QThread and so I came up with this solution but it still gets fishy though it's pretty nice. I'm open to any recommendation, this is my first time with QT so better to learn now than feel sorry later.
Oh my bad, I forgot the concrete actual question. Why doesn't the execution ends with a nice exit code of 0?
What I expect is that with handler->StartThread() statement the function within my thread start to write debug messages and once the internal timer within handler finishes I get the nice line [Press ...] and then a return code of 0. However this is not happening.
The reason you're not getting a finished command prompt of "[Press ...]" is due to the QCoreApplication and its exec() call. As the Qt docs state: -
Enters the main event loop and waits until exit() is called
So, you've created a second thread, set it to do some work and finish, but the main thread is still running. You need to exit the main thread.
And of course when I stop the execution of the application, the return code is: -1073741510
It sounds like you're killing the main thread with something like "Ctrl+C". Calling QCoreApplication::exit() when your 2nd thread finishes and has cleaned up, should help here.
Scenario
Lets say, I have a procedure called parallelRun. It would take a list of workers, each having a getWorkAmount():int, a run() method, a finished() signal and a cancel() slot:
void parallelRun( std::vector< Worker* > workers );
Its implementation should:
1. Open a QPogressDialog:
unsigned int totalWorkAmount = 0;
for( auto it = workers.begin(); it != workers.end(); ++it )
{
totalWorkAmount += ( **it ).getWorkAmount();
}
LoadUI ui( 0, totalWorkAmount, this );
with
class LoadUI : public QObject
{
Q_OBJECT
public:
LoadUI( int min, int max, QWidget* modalParent )
: totalProgres( 0 )
, progressDlg( "Working", "Abort", min, max, modalParent )
{
connect( &progressDlg, SIGNAL( canceled() ), this, SLOT( cancel() ) );
progressDlg.setWindowModality( Qt::WindowModal );
progressDlg.show();
}
bool wasCanceled() const
{
return progressDlg.wasCanceled();
}
public slots:
void progress( int amount )
{
totalProgres += amount;
progressDlg.setValue( totalProgres );
progressDlg.update();
QApplication::processEvents();
}
signals:
void canceled();
private slots:
void cancel()
{
emit canceled();
}
private:
int totalProgres;
QProgressDialog progressDlg;
}
2. Create one thread for each worker
std::vector< std::unique_ptr< QThread > > threads;
for( auto it = workers.begin(); it != workers.end(); ++it )
{
std::unique_ptr< QThread > thread( new QThread() );
Worker* const worker = *it;
worker->moveToThread( thread.get() );
QObject::connect( worker, SIGNAL( finished() ), thread.get(), SLOT( quit() ) );
QObject::connect( &ui, SIGNAL( canceled() ), worker, SLOT( cancel() ) );
QObject::connect( *it, SIGNAL( progressed( int ) ), &ui, SLOT( progress( int ) ) );
thread->start( priority );
threads.push_back( std::move( thread ) );
}
3. Run them simultaneously
for( auto it = workers.begin(); it != workers.end(); ++it )
{
QMetaObject::invokeMethod( *it, "run", Qt::QueuedConnection );
}
load() is run when the user clicks an UI-button.
Problem
How am I supposed to extend this code, if I want to make parallelRun block until all workers are finished, without freezing the QProgressDialog?
Deliberations
Using a barrier
I tried adding the following code at the end of the parallelRun routine:
QApplication::processEvents();
for( auto it = threads.begin(); it != threads.end(); ++it )
{
( **it ).wait();
}
The impact of this few lines of extra-code is, that LoadUI::progress is never entered, since the GUI-thread is asleep and therefore it's event loop isn't processed: In Qt, signals are delivered to slots by posting them to the event loop of the thread, associated to the object the slot belongs to. This is why the progressed signal of a worker is never delivered.
I think, the appropriate solution would be to run QApplication::processEvents() within the GUI-thread anytime a progressed signal is emitted by a worker. On the other hand, I guess this cannot be done, since the GUI-thread is asleep.
Another possible solution
Another possibility would be to use an active waiting-like solution:
for( auto it = threads.begin(); it != threads.end(); ++it )
{
while( ( **it ).isRunning() )
{
QApplication::processEvents();
}
}
for( auto it = threads.begin(); it != threads.end(); ++it )
{
( **it ).wait();
}
This also requires adding the following line of code right after thread->start( priority );:
while( !thread->isRunning() );
I don't think that this is a nice solution, but at least it works. How can this be done without the drawbacks of active waiting?
Thanks in advance!
You could use the threads' finished() signals to wait for them all to finish in the main GUI loop instead of using QApplication::processEvents. The progress dialog modality will ensure that only that dialog window is active until it is explicitly closed.
class WorkerManager : public QObject {
Q_OBJECT
private:
// to be able to access the threads and ui, they are defined as a members
std::vector<std::unique_ptr<QThread> > threads;
LoadUI *ui;
int finishedThreadCount;
public:
WorkerManager()
: finishedThreadCount(0)
{
// Open the QProgressDialog
...
// Create and start the threads
...
// Connect the finished() signal of each thread
// to the slot onThreadFinished
for( auto it = threads.begin(); it != threads.end(); ++it ) {
QObject::connect(
it->get(), SIGNAL(finished()),
this, SLOT(onThreadFinished()) );
}
}
private slots:
void onThreadFinished() {
++finishedThreadCount;
if(finishedThreadCount == threads.size())
{
// clean up the threads if necessary
// close the dialog
// and eventually destroy the object this itself
}
}
};
Or you can run a nested QEventLoop to wait for the threads to finish synchronously while still keeping the GUI responsive:
// Open the QProgressDialog
...
// Create and start the threads
...
// Create and run a local event loop,
// which will be interrupted each time a thread finishes
QEventLoop loop;
for( auto it = threads.begin(); it != threads.end(); ++it )
{
QObject::connect(
it->get(), SIGNAL(finished()),
&loop, SLOT(quit()) );
}
for(int i = 0, threadCount = threads.size(); i < threadCount; ++i)
loop.exec();
If the progress reach the maximum only when the work is completely done, you can use progressDlg->exec() instead of a QEventLoop which will block until the maximum is reached or until the user clicks on the "Cancel" button.
Instead of building your own. Maybe QThreadPool is what you are looking for?
QThreadPool has a function for waiting for all workers.