Use QWaitCondition in a thread started by QtConcurrent - qt

i have a function that is started by a QTconcurrent run. Inside this function i use QThread (To get the Thread created by the QTConcurrent run) static method to sleep it for some time, but i don't want anymore to use time to activate it, i'd like to use a WaitCondition to wake the thread in another point of the execution, but i searched a lot and don't find any case like this. I only see WaitConditions inside run() methods. Is there some way to use QWaitCondition in a thread started by QtConcurrent?

You also need a mutex:
void work(QMutex* mutex, QWaitCondtion* cond, volatile bool* wake){
//do work
{
QMutexLocker locker(mutex);
while(!*wake){
cond->wait(mutex);
}
}
//do more work
}
The loop is necessary to avoid spurious wakeups and let the thread fall through if wake is already set to true. Locking over the entire loop is needed to avoid various race conditions.
You wake the thread with:
{
QMutexLocker locker(mutex);
*wake = true;
cond->wakeOne();
}

Related

Qt - start process with click event and stop it again with the second click event

I found time to investigate a bit into QT, and it is very interesting for me. However, right now I am encountering a problem that I am not aware about how to solve it. My aim is actually simple. I have a QCheckBox that I want to activate. If it is activated, I am starting a process (I am opening a file, reading it, taking some values out and change different labels accordingly). This process is repeated until the user is deactivating the QCheckBox. Some small code example to get a better idea of what I am going to do.
void Analyzer::on_actualTemperature_stateChanged(int arg1)
{
// Read data and change labels
if (arg1 != 0)
{
qDebug() << "Start data analysis";
// Infinity loop to get the data and display it
while true
{
// Open file and extract data
const actualTemperature = getData();
// Change any label or do something with the data
ui->anyLabel->setText(actualTemperature);
// Some break
QThread::sleep(1);
// Leave the loop if user deactivate the QCheckBox
// Something like on_actualTemperature_stateChange == 0
}
}
// Stop reading the data
else
{
qDebug() << "Stop data analysis";
}
}
It is obvious that after activating the QCheckBox, the loop will not finish at all and the GUI will not recognize anything anymore. Hence, I guess I have to start some new thread and have to kill it. However, I have no idea how to proceed here. An idea would be:
void Analyzer::on_actualTemperature_stateChanged(int arg1)
{
// Read data and change labels
if (arg1 != 0)
{
// Start reading the file and updating the label using some other thread
startThread(XY);
}
// Stop reading the data
else
{
// Kill thread 1234
killThread(XY);
}
}
Any hint is warmly welcomed and I hope this question is not too basic for you. Thank you for reading, Tobi.
I think killing a running thread is not a decent behavior. Let's be gentle to our threads with a loop control variable. In this example it named keepLoop. Set keepLoop when checkbox checked. Then start thread if it is not running. We are using QtConcurrent::run, and monitoring it by a QFuture in this case.
connect(ui->checkBox, &QCheckBox::toggled,
[&](const bool checked) {
analyzer->keepLoop = checked;
if (checked && !future.isRunning())
future = QtConcurrent::run(analyzer, &Analyzer::on_actualTemperature_stateChanged);
}
);
Don't call user interface slots directly, instead connect them to signals. Connections will be queued connection when signals emitted from another thread. It means slots will be called in event loop of main thread and changes will be shown when the next frame painted.
connect(analyzer, &Analyzer::temperatureCalculated, ui->anyLabel, &QLabel::setText);
Our asynchronous function does not forced to die immediately when user toggle checkbox. Instead we letting it to finish the iteration it already on halfway through.
Analyzer::on_actualTemperature_stateChanged() {
while (keepLoop) {
// Open file and extract data
const QString& actualTemperature = getData();
// send data
emit temperatureCalculated(actualTemperature);
}
}
You can use atomic bool if you want a more precise loop control.
Bonus:
If you don't want to mess with threads, you can avoid GUI freezing by using QTimer to run your loop periodically in main thread.

Terminating QProcess in a destructor

A have a problem trying to stop my QProcess in it's parent destructor. Here is my code:
AbstractProcess::~AbstractProcess()
{
if((m_process->state() == QProcess::Running)
|| (m_process->state() == QProcess::Starting))
{
m_process->terminate();
m_process->waitForFinished();
}
}
m_process is a pointer to QProcess. In AbstractProcess's constructor I have this code:
m_process = new QProcess(this);
So, when AbstractProcess is deleted I get to it's destructor and I have a segmentation fault at :
m_process->waitForFinished();
Can anybody tell me what my mistake is?
UPD:
As was said below in the comments the problem was not in the code that I provided. Very sorry for that. So I will try to explain what the problem was. Maybe it will help somebody. AbstractProcess as you might guess by the name is an abstract class. So it has some pure virtual functions. On of them is:
virtual void onProcessFinished(int exitCode, QProcess::ExitStatus
exitStatus) = 0;
The full body of my constructor is:
m_process = new QProcess(this);
connect(m_process,static_cast<void(QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished),
this, &AbstractProcess::onProcessFinished);
And now it's obvious that on calling waitForFinished the process emits signal finished and the pure virtual function is called. That leads to undefined behaviour. To fix this I call disconnect before stopping my process. The destructor now looks like this:
AbstractProcess::~AbstractProcess()
{
disconnect(m_process,static_cast<void(QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished),
this, &AbstractProcess::onProcessFinished)
if((m_process->state() == QProcess::Running)
|| (m_process->state() == QProcess::Starting))
{
m_process->terminate();
m_process->waitForFinished();
}
}
Thanx everybody for your help.
When you call m_process->terminate(); first, there is no guarantee that the process will exit .. yet there is no guarantee that the process will continue to exist because of calling (WM_CLOSE on windows / SIGTERM on Linux) so calling for m_process->waitForFinished(); on a process that might have already been terminated might cause segmentation fault.
the right and safe approach is to do the right things in order:
m_process->waitForFinished();
m_process->terminate();

Force threads to wait for other threads to complete their jobs before going further?

suppose I have a thread class with run method like this :
void run()
{
while(1){
first_job();
//__Syncthreads();
second_job();
}
}
I have 3 threads and I want all of them do first_job() and wait for other to accomplish first_job() before they going for second_job()
I know that there is something called QWaitCondition but I think I need an extra thread. Am I true?

How to implement "first come first served" scheduling algorithm using threading in Qt C++ programming?

I wish to add processes to a dynamic list then schedule those processes using the "first come first served" scheduling algorithm. The scheduling algorithm should only run a max of 5 processes concurrently and when a process has been terminated it should it should emit a signal to indicate termination.
Then when a process has been terminated, another process should be scheduled by the scheduling algorithm once there are processes in the queue.
Note also that each process has access to a shared list of integer which only one process can access at a time. I already know how to do this part by locking the shared integer list using QMutex. Ideally, I am seeking an example, so I can understand it.
//mutex example
QMutex mutex
while(!mutex->tryLock()){
//enter code here
}
this->performTask(); //
mutex.unlock();
You will have 5 instances of a class that extends QThread. Each class will execute a QProcess and wait for it to finish.
class MyThread : public QThread
{
public:
MyThread(MyScheduler& aScheduler)
: iScheduler(aScheduler)
{
}
void ExecuteProgram(const QString& aProgramName)
{
iProgramName = aProgramName;
start();
}
void run()
{
iProcess.start(iProgramName);
iProcess.waitForFinished(-1);
iScheduler.SignalProgramTerminated(this);
}
private:
MyScheduler& iScheduler; // This is your FCFS scheduler.
QString iProgramName;
QProcess iProcess;
};
(I haven't compiled this but it should give you some headway).
You could use QThreadPool to create a pool of 5 threads that run your processes and use QQueue to queue the pending processes in a FIFO fashion.
edit:
About mutexes:
The mutex protects a piece of code form beeing executed by more than one thread. A thread tying to lock a mutex will be blocked until no other thread holds the lock. The easiest way to use mutexes is with the QMutexLocker.
void myclass::modifyList(IntegerList* list)
{
QMutexLocker lock(list->getMutex()); //this will block if an other thread holds the mutes
//do stuff
}

Qt: How to delay a program while QTimer is active?

Please refer to the following link as I tried to simplify the problem I was having and now have run into a problem that I cannot solve.
Link: Qt: How to use QTimer to print a message to a QTextBrowser every 10 seconds?
In the posting for the link above I simplified the task I am trying to do by simply saying that I wanted to push a button and have it display something in a QTextBrowser every 10 seconds. I was having trouble getting QTimer working at the time so I thought that if I could get QTimer to work then I could finish my task.
What I am really trying to do is read lines from a file and after every 2500 lines I would like to print a message and then wait 10 seconds.
Pseudocode:
while(not at the end of the file)
{
read in 2500 lines
print a message
wait 10 seconds
}
QTimer is nice but it does opposite of what I want it to do. Instead of transmitting a message and waiting 10 seconds, first they wait 10 seconds, timeout and then send the message.
So to get it to work the way I want I first called the printMessage() SLOT and then I made a SLOT called stopTimer() that simply stops the timer. So after the 10 seconds has passed it will simply call stopTimer() and then continue processing the input file.
Onto the REAL problem:
Qt does not wait for a QTimer to finish before it moves on through the code. I want the code to wait the full 10 seconds before it reads the next 2500 lines of code. I found that QTimer has an isActive() function that returns a bool value.
So in the place where I wanted the 10 second delay to finish I put the following:
while(timer->isActive());
I figured the program would stay in this loop for 10 seconds and then exit after the QTimer timed out because the condition would then be false. The problem is that it doesn’t exit the loop because the status of the timer never changes regardless of how long it waits in this loop! I checked with the debugger and isActive( ) remains true regardless of elapsed time.
I then omitted the while(timer->isActive()) loop and observed the timer in the debugger. It seems that the timer does not actually start timing until it exits the while(not at the end of the file). So I believe that since the while(timer->isActive()) loop is nested inside this, it is causing it to never timeout. I could be wrong but this is what seems like is happening. Also, what is annoying is that the QTimer object has no field that shows the elapsed time of the timer when it is active. Therefore, I cannot check the elapsed time at all to further debug.
Someone please test this out or let me know a workaround for this!
For something that sounds so easy, this has been the biggest pain I have had in recent time, but I generally don’t use Qt so it could be my lack of experience.
Here is an excerpt from code I have which currently freezes as stated above:
void Form::startBtn_pushed()
{
QTimer *timer = new QTimer(this);
QFile file(“file.txt”);
QTextStream stream(&file);
QString line;
int lineCount = 0;
connect(timer, SIGNAL(timeout()), this, SLOT(stopTimer()));
while(!(stream.atEnd())
{
line = stream.readLine();
lineCount++;
if(lineCount == 2500)
{
printMessage();
timer->start(10000);
while(timer->isActive()); //Wait for timer to timeout before continuing
}
}
}
Sorry for the long post and if I might have made any grammatical errors with my code here. I do not have internet access on my dev machine so I had to retype this here.
Doing something like while(timer.isActive()) is not a good idea at all as it will cause your application to consume around 100% CPU time. It will also cause your application to never return to the event processing loop where the actual code for timer is executed, that's why it freezes.
If you still want to use this approach, you should call QCoreApplication::processEvents() in the loop. It will temporarily pass control back to the event loop, so it will cause timer to time out. Instead of connecting timeout() to stopTimer(), you can just call timer.setSingleShot(true) before you start it, it will cause it to stop automatically after the first timeout.
Note that you have a memory leak there as you create a new timer on each button push. Surely they are children of your form and will be destroyed, but only when the form is destroyed.
If you want a more elegant approach, you can create a separate class for reading that file. In the constructor you'd open your file and stream which should be fields in this class. This class should also have a sort of readMore() slot which will read 2500 lines, then put a message and return. If it doesn't reach the end of the stream, then it would call QTimer::singleShot(10000, this, SLOT(readMore())), which will cause the event loop to call readMore() again in 10 seconds. The code would looks something like this (didn't check for errors):
// myfilereader.h
class Form;
class MyFileReader: public QObject {
Q_OBJECT
public:
MyFileReader(const QString &fileName);
// this should be called after you create an instance of MyFileReader
void startReading() {readMore();}
private:
QFile file;
QTextStream stream;
private slots:
void readMore();
signals:
void message(); // this should be connected to printMessage() in the Form
void finished();
};
// myfilereader.cpp
MyFileReader::MyFileReader(const QString &fileName):
file(fileName),
stream(&file),
{
// open the file, possibly throwing an exception
// or setting some sort of "invalid" flag on failure
}
void MyFileReader::readMore()
{
QString line;
int lineCount = 0;
while(!(stream.atEnd())
{
line = stream.readLine();
lineCount++;
if(lineCount == 2500)
{
emit message();
break;
}
}
if (stream.atEnd())
emit finished();
else
QTimer::singleShot(10000, this, SLOT(readMore()));
}
This is a kind of more heavyweight approach, but this is the price of asynchronous event handling. You could also put all this stuff into the Form class, but I think using a separate class is better.
As Daniel points out, if reading 2500 lines takes a long time, say 5 seconds, the message will be printed after 10 seconds after the reading has finished, that is, 15 seconds after it has started. If you want the message to be printed approximately each 10 seconds no matter how long reading takes, you should add a QTimer timer field to the class, connect it's timeout() signal to the readMore() slot in the MyFileReader constructor, then in the startReading() method call timer.start() before calling readMore(). Now, at the end of readMore() do this:
if (stream.atEnd()) {
timer.stop();
emit finished();
}
You need a QTimer field in this case because you can't cancel a QTimer::singleShot() call, but you need to do it if you have reached the end of the stream, otherwise your readMore() will just keep on getting called again and again, even if there is nothing more to read. Note that even in this case, it is still possible for the message to appear less frequently than every 10 seconds in case if reading 2500 lines takes longer than these 10 seconds. If you want exactly 10 seconds, you should probably check the elapsed time in the loop instead, but I think that's an overkill, unless you expect reading to be very slow.
Slightly off topic, but if you want an easy way to avoid memory leaks, you can also do this in the constructor:
connect(this, SIGNAL(finished()), this, SLOT(deleteLater()));
It will automatically mark your reader for deletion when you emit finished(), and, once that happens, the reader will be deleted as soon as the control goes back to the event loop. That is, after all slots connected to the finished() signal return. This approach allows you to just allocate a MyFileReader on the heap, then discard the pointer without worrying about memory leaks.
QTimer has a signal called timedout(). If you connect a slot to this, you can set the initial timer to a REALLY short interval (1 MS maybe). When the timer expires, inside the slot, you can send your message. At the end of the slot, set the interval to 10 seconds, set singleshot to false, and the start the timer again.
If you don't want to do the setting each and every time the slot is called, you can simply make 2 slots. The first time, the slot does the setup for the rest of the calls. It also disconnects itself from the QTimer and connects the second slot. Then things continue merrily on their way.
Edit:
Also, realize that when slots are called they are called on the event thread. So, by clicking a button and putting a loop that spin-blocks/busy-waits until the timer expires, you are guaranteeing that you will not enter this state because you are blocking the very thread that the timeout signal will be processed on.
QTimer does all of its processing inside Qt's event loop, so your code must return to the event loop to cause the timer to time out. So what you want to do is have startBtn_pushed set up the timer, connect a slot to the timer's timeout signal, then probably call that slot itself (so that it is called immediately). It would look something like this:
// timer, file, and stream are now instance variables (or maybe file and stream
// are broken out into their own class... up to you.
void Form::startBtn_pushed()
{
// timer has been allocated before (but not started)
file.open(“file.txt”);
stream.setDevice(&file);
connect(timer, SIGNAL(timeout()), this, SLOT(readAndPrint()));
timer->start(10000);
readAndPrint(); // respond to the button press immediately
}
void Form::readAndPrint()
{
int lineCount = 0;
while(!(stream.atEnd() && lineCount < 2500)
{
line = stream.readLine();
lineCount++;
if(lineCount == 2500)
{
printMessage();
}
}
}
I have figured out a solution that is much simpler than those proposed here.
I realized it was much easier to use a QTime object instead of a QTimer object.
Basically you start a QTime object and then you use its elapsed() function to check how much time has passed to since it was started.
Thanks to everyone for taking the time to help. I did try to implement a couple of your solutions into my code but had some trouble since I am not a pro at Qt and they were more complex than I would have thought. In the end I find this solution to be a easy solution to what should have been an easy problem.
I certainly learned a lot from this problem and I hope you all did too.
My question to you is why didn't anyone suggest using QTime from the start?
Thanks again!
My solution:
void Form::startBtn_pushed()
{
QTime *timer = new QTime();
QFile file(“file.txt”);
QTextStream stream(&file);
QString line;
int lineCount = 0;
connect(timer, SIGNAL(timeout()), this, SLOT(stopTimer()));
while(!(stream.atEnd())
{
line = stream.readLine();
lineCount++;
if(lineCount == 2500)
{
timer->start();
while(1)
{
QApplication::processEvents();
if(timer->elapsed() == 10000)
{
printMessage();
break;
}
}
}
}
}
QEventLoop l;
connect( timer, SIGNAL( timeout() ), &l, SLOT( quit() ) );
l.exec(); // Waiting without freezing ui

Resources