Qt: QFuture/QtConcurrent timeout function call - c++

I need a timeout function call. I work mainly with Qt (4.7.3, 4.8.5) and so i tried to find a solution with Qt. The two classes QFuture and QtConcurrent seems to do 99% of what i need but i can not find a possibility to timeout a function call.
My Problem:
I have my tester (gtest) and i test a function which can end in an infinity loop => so i want to test this to fix that problem[s] (this function is internal extrem complex :-( ). I want to add a timeout-time to break out if there is an infinity loop => so i can tell the tester that something is wrong (infinity loop) and i will terminate the thread.
I have search for something like that:
QtConcurrent::run(............,30000 /*30 seconds timeout)*/;
Does anybody know how i can do this?
(If it is possible with native C++, or boost, or ... you can also tell me your solution)

I was focusing on the QtConcurrent module, since you mentioned it in your question. But you can achieve your goal also with plain QThread:
// A Thread calling your test function
class MyThread : public QThread {
protected:
void run() { myFunction(); }
};
// calling the function
MyThread t;
t.start();
if ( t.wait(30000) ) {
// Finished
} else {
// Not finished
// ATTENTION: USE TERMINATE WITH CARE (see QThread documentation)!
t.terminate();
}
The call to terminate will forceably stop the thread and thus stop the execution of your function. Note however that the thread cannot cleanup, and any resources used by your function are not freed properly.
Old Answer:
You can do this with Qt, using a QFutureWatcher, a QTimer, and a helper QEventLoop . Setup your concurrent run, and watch the result with the watcher. Set the Timout with the timer, and wait until either is finished, in a Event loop.
// Setup eventloop, watcher and timer
QEventLoop loop;
QFutureWatcher watcher;
QObject::connect( &watcher, SIGNAL(finished()), &loop, SLOT(quit()));
QTimer::singleShot( 30000, &loop, SLOT(quit()) );
// Start function call
QFuture<T> future = QtConcurrent::run(...);
// Watch the call
watcher.setFuture( future );
// Wait until event loop finishes
loop.exec();
// Now either future has finished, or timeout was reached...
if ( future.isFinished() ) {
// Function completed!
} else {
future.cancel();
// Infinite loop...
}

The issue is that you cannot safely terminate a thread without thread's cooperation. The thread may be accessing some shared data structure, like the C-runtime heap, and if it is terminated forcefully then such data structures will remain in a mid-change state, essentially corrupted. Any future access to them from within the program will likely cause a crash or worse.
The case of an infinite loop is not by any means different from other bad scenarios. What if the function you launch crashes the program, how do you report it to the tester?
In your case you simply don't trust the code that you're executing. The solution is to launch it in a separate process, whose safe termination is guaranteed by the operating system. By isolating the tested code from the tester application you guarantee that you can detect all kind of problems, including timeouts or abnormal termination.

I think you need to find out why the infinite loop happens rather than trying to fix symptoms.
QtConcurrent::run() uses thread pool to run tasks. You can't safely terminate thread, so the only way to safely finish a task is to return from it.
If you still want timeouts, you can add something like this to your function with loop:
QTime t;
t.start();
// it's your loop
while( true ) {
if( t.elapsed() > 30*1000 ) {
return 1;
}
...
}

You can bind a QTimer signal to the slot:
auto process = QtConcurrent::run(...);
QTimer& timer = new QTimer();
connect(timer, &QTimer::timeout, [=, &process]() {
process.cancel();
});
timer->start(3000);
Edit: As the cancel() method won't work on the QtConcurrent::run function, the easiest thing would be to use some kind of isRunning flag:
bool isRunning = true;
void runnable() {
while (isRunning) {
...
}
}
auto process = QtConcurrent::run(runnable);
QTimer& timer = new QTimer();
connect(timer, &QTimer::timeout, [=, &isRunning]() {
isRunning = false;
});
timer->start(3000);

Related

Qthread deleteLater() crashing program

QT 4.8: I have been getting a number of segment faults and I/O Possible errors in my code that I cannot figure out. From print statements I have seen a number of odd and inconsistent behaviors, likely indicating race conditions. Many times everything works perfect. Sometimes I get an I/O error immediately after the worker destructor is called, indicating main connect deleteLater() issue. Other times if I try to delete audioOutput in destructor it will work a number of times then give me a segment fault (or I/O) randomly in middle of destructor on other attempts. I believe my issues can be attributed to 2 things, worker cleanup/ connect quit()/deletelater() calls and my recursive loop in worker which needs to create its own event loop every time thus possibly emitting finished signal before the previous calls can be cleaned up?
Specifically my questions are:
What could cause deleteLater() to create an I/O Possible error?
how should I delete pointers inside of worker class so they are deleted at the correct time (end)... or does QT handle this for me?
Gui and .h
QByteArray* qbyte;
QThread* thread;
PlayAudio* audioWorker;
MainWindow::startSound()
{
QFile soundFile;
soundFile.setFileName("/home/sounds/sound.wav");
qbyte = new QByteArray(soundFile.readAll());
soundFile.close();
thread= new QThread;
audioWorker= new PlayAudio(qbyte, 5);
audioWorker->moveToThread(thread);
connect(thread, SIGNAL(started()), audioWorker, SLOT(play()));
connect(audioWorker, SIGNAL(finished()), thread, SLOT(quit()));
connect(audioWorker, SIGNAL(finished()), audioWorker,SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), this, SLOT(donePlaying()));
}
MainWindow::donePlaying()
{
//do stuff
}
Worker class and .h
QByteArray qbyte;
int numOfPlays;
int numOfPlaysRun;
bool quit = false;
QBuffer *qbuff;
QAudioFormat format;
QAudioOutput *audioOutput;
PlayAudio::PlayAudio(QByteArray *qbyte_, int num)
{
qbyte=*qbyte_;
numOfPlays=num;
qbuff=new QBuffer();
qbuff->setData(qbyte);
qbuff->open(QIODevice::ReadOnly);
//set format
audioOutput = new QAudioOutput(format,this);
connect(audioOutput,SIGNAL(stateChanged(QAudio::State)),
SLOT(finishedPlaying(QAudio::State)));
}
void PlayAudio::::play()
{
if (!quit)
{
audioOutput->start(qbuff);
QEventLoop loop;
do {
loop.exec();
} while(!quit);
}
}
void PlayAudio::finishedPlaying(QAudio::State state)
{
if (state == QAudio::IdleState)
{
if (numOfPlaysRun< numOfPlays && !quit)
{
numOfPlaysRun++;
play();
}
else
{
//should i ever stop loop myself? or is that done from main?
//quit=true;
emit finished();
}
}
}
PlayAudio:: ~PlayAudio()
{
// still have qbuff and audioOutput to delete. If i do here i sometimes
//get segment faults or IO error.
}
updated:
still have intermittent issues but commenting out the following line has helped clear some of them in combination with setting quit=true.
connect(audioWorker, SIGNAL(finished()), audioWorker,SLOT(deleteLater()));
But this may cause a memory leak?
Update 2:
I'm starting to think I'm talking to myself here but I think I got it. It appears this was a timing issue as the thread was returning finished() prior to the worker actually finishing due to the time to unwind from quit() signal that closes the open loops once the worker emits finished(). So I now emit a custom signal from worker for every loop closed and track this in main. Once I receive what I expect I then release wait() and delete the thread THEN then worker. Not sure if this is correct but it seems to be working. Seems hackish to me but IMO the thread shouldn't return finished until the worker does, seems pointless then. but oh well.

What exactly happens with QTimer start function?

I have the following code:
mytimer.cpp
#include "mytimer.h"
#include <QtCore>
MyTimer::MyTimer()
{
timer = new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(mySlot()));
timer->start(1000);
}
void MyTimer::mySlot()
{
qDebug()<<"timer executed";
}
and in the main.cpp
#include <QCoreApplication>
#include "mytimer.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyTimer mtimer;
qDebug()<<"DONE";
return a.exec();
}
Now the output comes as:
DONE
timer executed
timer executed
...
...
...
...
infinite sequence
I am really confused by this. How is that we are done with our main function and still the code for the SLOT mySlot() is getting executed?
What are the important aspects to this? that I need to understand?
Also what changes occurs when I modify mytimer.cpp MyTimer() to:
MyTimer::MyTimer()
{
timer = new QTimer(this);
QEventLoop eventloop;
connect(timer,SIGNAL(timeout()),this,SLOT(mySlot()));
connect(timer,SIGNAL(timeout()),&eventloop,SLOT(quit()));
timer->start(1000);
eventloop.exec();
}
There is one timer executed just before DONE is printed. To Be specific the output now becomes:
timer executed
DONE
timer executed
timer executed
...
...
...
...
infinite sequence
What caused that separate timer executed to appear above the DONE?
No - your main function is not done. It called a.exec() which will never return in your application.
a.exec() in turn processes a "message queue" which triggers all the timer events that call mySlot().
a.exec starts the event loop. It doesn't return a value until either QApplication::exit() or QApplication::quit() or all windows are closed.
What caused that separate timer executed to appear above the DONE?
The timer signals are always emitted from within the outermost event loop - because that's where the locus of control is (i.e. that's where the thread is running - it's inside Qt). Since you spun a local event loop (eventloop.exec();), that's where the timer invocation came from. As soon as that event loop was done and that exec() had returned, the MyTimer constructor had exited, DONE was printed out, and remaining timer invocations happen from the main event loop.
Generally speaking, code that nests event loops is broken, so if you ever find yourself with more than one exec() on the call stack, you're doing it wrong. There are a few notable exceptions: native dialogs on OS X require their own nested event loop due to OS X API deficiencies, and QDrag requires exec() also most likely due to platform deficiencies that require an exec() for portability, even if on some platforms it'd be unnecessary.

Start QTimer from another non-gui thread

I try to start QTimer from another thread ( to get better accuracy ).
I think that problem is with function connect but let see my code:
//code from constructor of parent.cpp class
{
//run_clock_timer(this); // this works
std::thread t1{ [this] { run_clock_timer(this); } }; //not works
t1.join();
}
And function:
void class::run_clock_timer(class* inst){
QTimer * test = new QTimer(inst);
connect(test, SIGNAL(timeout()), inst, SLOT(updateTime()));
test->setInterval(50);
test->start(timer_precision);
}
Debugger told me that code from run_clock_timer was run, but no result.
I think i will do it with no problem when i use QThread, but i want to use std::thread.
So whats wrong with my function ?
The problem is that QTimer depends on the ability to interact with a running Qt event loop in order to perform its task. Since a non-Qt thread has no event loop, the QTimer can't do its job. (i.e. there has to be some Qt code running in the thread, that will emit the timeout() signal, that doesn't just happen on its own)

std::thread consumes all CPUs in Qt

I have a function. In my function there is a c++ thread & a Qtimer. By c++ thread I receive ARP Reply packets & by QTimer I send ARP Request packets.
The simplified structure:
int foo()
{
... some codes ...
QTimer::singleShot(1000, this, SLOT(beginSending()));
std::thread tCapture(Capture);
tCapture.join();
return 0;
}
void Capture()
{
while ( ! finishCapturing )
{
do sth
}
}
In the tCapture thread I have a while loop that consumes all CPUs & the Qtimer does not work!
I use .join() because I want to wait for the thread to finish.
when I set finishCapturing flag in Qtimer slot, the thread will be finished.
The above codes don't work correctly, because the c++ thread consumes all CPUs!
what is the problem?
Thanks a lot.
Ya Ali.
The problem is joining the thread right after creating them, that blocks the GUI thread and the QTimer and all slots on that thread.
What you should do is emit a signal when capturing is done;
public void beginSending(){
//do sending and capture
finishCapturing =true;
emit finshedCapture();
}
If needed you can put the body of the while in a slot and have it called repeatedly with a QTimer with a timeout of 0 (which means the slot will get called as often as possible).
then you can connect the finshedCapture() signal to the stop() slot of the QTimer
int foo()
{
... some codes ...
QTimer::singleShot(1000, this, SLOT(beginSending()));
QTimer* timer = new QTimer(this);
connect(timer, signal(timeout()), this, slot(Capture()));
connect(this, signal(finshedCapture()), timer, slot(stop()));
connect(this, signal(finshedCapture()), timer, slot(deleteLater()));//cleaup when done
timer->setTimeout(0);
timer->setSingleShot(false);
timer->start();
return 0;
}
void Capture()
{
//no while because the timer will call it as needed
//do sth
}
Without seeing more of the code, this is guess-work:
1: Capture() does not block, so will consume as much CPU time as the operating system gives it - which will be 100% of one CPU on a lightly loaded multi-core system.
2: foo() is called on the main thread. It then attempts to join() with the your thread - which blocks until the thread finished. I see nothing setting finishCapturing, so it doesn't.
3: The QTimer is dispatched through the run-loop - which is blocked.
In effect, this is deadlock of the main thread.

How can I protect a QThread function so it will not be called again until finished its previous work?

I'm using a QThread and inside its run method I have a timer invoking a function that performs some heavy actions that take some time. Usually more than the interval that triggers the timer (but not always).
What I need is to protect this method so it can be invoked only if it has completed its previous job.
Here is the code:
NotificationThread::NotificationThread(QObject *parent)
: QThread(parent),
bWorking(false),
m_timerInterval(0)
{
}
NotificationThread::~NotificationThread()
{
;
}
void NotificationThread::fire()
{
if (!bWorking)
{
m_mutex.lock(); // <-- This is not protection the GetUpdateTime method from invoking over and over.
bWorking = true;
int size = groupsMarkedForUpdate.size();
if (MyApp::getInstance()->GetUpdateTime(batchVectorResult))
{
bWorking = false;
emit UpdateNotifications();
}
m_mutex.unlock();
}
}
void NotificationThread::run()
{
m_NotificationTimer = new QTimer();
connect(m_NotificationTimer,
SIGNAL(timeout()),
this,
SLOT(fire(),
Qt::DirectConnection));
int interval = val.toInt();
m_NotificationTimer->setInterval(3000);
m_NotificationTimer->start();
QThread::exec();
}
// This method is invoked from the main class
void NotificationThread::Execute(const QStringList batchReqList)
{
m_batchReqList = batchReqList;
start();
}
You could always have a thread that needs to run the method connected to an onDone signal that alerts all subscribers that it is complete. Then you should not run into the problems associated with double lock check and memory reordering. Maintain the run state in each thread.
I'm assuming you want to protect your thread from calls from another thread. Am I right? If yes, then..
This is what QMutex is for. QMutex gives you an interface to "lock" the thread until it is "unlocked", thus serializing access to the thread. You can choose to unlock the thread until it is done doing its work. But use it at your own risk. QMutex presents its own problems when used incorrectly. Refer to the documentation for more information on this.
But there are many more ways to solve your problem, like for example, #Beached suggests a simpler way to solve the problem; your instance of QThread would emit a signal if it's done. Or better yet, make a bool isDone inside your thread which would then be true if it's done, or false if it's not. If ever it's true then it's safe to call the method. But make sure you do not manipulate isDone outside the thread that owns it. I suggest you only manipulate isDone inside your QThread.
Here's the class documentation: link
LOL, I seriously misinterpreted your question. Sorry. It seems you've already done my second suggestion with bWorking.