How to fix "In Qt two timer to one function, use qmutex will qeventloop for sleep" - qt

I have some code use qtcpsocket to write and read,
write-->sleep-->read;
and ui had 2 and more timer to use this function; by i want i run synchronous;so i add mutex to lock it; by it deadlock;
qt4; qt5;
void MainWindow::Start()
{
pTimer = new QTimer(this);
pTimer->setInterval(100);
connect(pTimer,SIGNAL(timeout()), this, SLOT(OnTimer()) );
pTimer->start();
pTimer2 = new QTimer(this);
pTimer2->setInterval(100);
connect(pTimer2,SIGNAL(timeout()), this, SLOT(OnTimer()) );
pTimer2->start();
}
void MainWindow::OnTimer()
{
FunCal(); // in my real code it will MyObj.DoSometing();
}
void MainWindow::FunCal()
{
qDebug()<<"log in fun...";
QMutexLocker loc(&this->_mtx);
qDebug()<<"getted lock in fun...";
QEventLoop loop;
QTimer::singleShot(100, &loop, SLOT(quit()));
loop.exec();
qDebug()<<"log out fun...";
}
I Want i run and out put as:
log in fun...
getted lock in fun ...
log out fun...
log in fun...
getted lock in fun...
log out fun...
but It Run like this:
log in fun...
getted lock in fun ...
log in fun....
---------------------------------no more ---------------------

IMHO the issue of OP results from a basic misunderstanding:
QTimer doesn't introduce multithreading.
It's just a facility to queue events which will sent after a certain time.
That's why, the QEventLoop is necessary to make it running at all.
However, it's still a deterministic execution and this is what probably happens inside the code of OP:
pTimer->start(); → starts first timer
pTimer2->start(); → starts second timer
control flow returns to event loop of QApplication (not exposed in code)
first timer becomes due and calls MainWindow::FunCal()
qDebug()<<"log in fun..."; → output of log in fun...
QMutexLocker loc(&this->_mtx); → this->_mtx becomes locked
qDebug()<<"getted lock in fun..."; → output of getted lock in fun...
loop.exec(); → enter a nested event loop (Nested event loops are allowed in Qt.)
second timer becomes due and calls MainWindow::FunCal() (Please, remember that it was immediately started after first with same interval time.)
qDebug()<<"log in fun..."; → output of log in fun...
QMutexLocker loc(&this->_mtx); → PROBLEM!
To illustrate it further, imagine the following call stack at this point (above called below):
QApplication::exec()
QEventLoop::exec()
QEventLoop::processEvents()
QTimer::timerEvent()
QTimer::timeOut()
MainWindow::onTimer()
MainWindow::FunCal()
QEventLoop::exec()
QTimer::timerEvent()
QTimer::timeOut()
MainWindow::onTimer()
MainWindow::FunCal()
QMutexLocker::QMutexLocker()
QMutex::lock()
(Note: In reality, you will see much more entries in the call-stack which I considered as irrelevant details in this case.)
The problem is: This second call of MainWindow::FunCal() cannot lock the mutex because it is already locked. Hence, the execution is suspended until the mutex is unlocked but this will never happen. The locking of mutex happened in the same thread (in the first/outer call of MainWindow::FunCal()). Unlocking would require to return from this point but it cannot because it's suspended due to the locked mutex.
If you think this sounds like a cat byting into its own tail – yes, this impression is right. However, the official term is Deadlock.
The usage of a QMutex doesn't make much sense as long as there are no competing threads. In a single thread, a simple bool variable would do as well because there are no concurrent accesses possible in a single thread.
Whatever OP tried to achieve in this code: Concerning the event-based programming forced/required by Qt, the problem is simply modeled wrong.
In single threading, a function cannot be entered twice accept by
a (direct or indirect) recursive call
a call out of a triggered interrupt handler.
Leaving the 2. aside (irrelevant for OPs Qt issue), the recursive call happens explicitly due to establishing a second (nested) event loop. Without this, the whole (mutex) locking is unnecessary and should be removed as well.
To understand event-based programming in general – it's described in the Qt doc. The Event System.
Additionally, I found Another Look at Events by Jasmin Blanchette which IMHO gives a nice little introduction into how the Qt event-based execution works.
Note:
Event-based programming can become confusing as soon as the amount of involved objects and signals becomes large enough. While debugging my Qt applications, I noticed from time to time recursions which I didn't expect.
A simple example: A value is changed and emits a signal. One of the slots updates a Qt widget which emits a signal about modification. One of the slots updates the value. Hence, the value is changed and emits a signal...
To break such infinite recursions, a std::lock_guard might be used with a simple DIY class Lock:
#include <iostream>
#include <mutex>
#include <functional>
#include <cassert>
// a lock class
class Lock {
private:
bool _lock;
public:
Lock(): _lock(false) { }
~Lock() = default;
Lock(const Lock&) = delete;
Lock& operator=(const Lock&) = delete;
operator bool() const { return _lock; }
void lock() { assert(!_lock); _lock = true; }
void unlock() { assert(_lock); _lock = false; }
};
A sample object with
a property-like member: bool _value
a simplified signal emitter: std::function<void()> sigValueSet
and a lock used to prevent recursive calls to setValue(): Lock _lockValue
// a sample data class with a property
class Object {
private:
bool _value; // a value
Lock _lockValue; // a lock to prevent recursion
public:
std::function<void()> sigValueSet;
public:
Object(): _value(false) { }
bool value() const { return _value; }
void setValue(bool value)
{
if (_lockValue) return;
std::lock_guard<Lock> lock(_lockValue);
// assign value
_value = value;
// emit signal
if (sigValueSet) sigValueSet();
}
};
Finally, some code to force the lock into action:
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
DEBUG(Object obj);
std::cout << "obj.value(): " << obj.value() << '\n';
DEBUG(obj.sigValueSet = [&](){ obj.setValue(obj.value()); });
DEBUG(obj.setValue(true));
std::cout << "obj.value(): " << obj.value() << '\n';
}
To keep things short, I connected a slot to the signal which directly sets value again while the signal is emitted.
Output:
Object obj;
obj.value(): 0
obj.sigValueSet = [&](){ obj.setValue(obj.value()); };
obj.setValue(true);
obj.value(): 1
Live Demo on coliru
For a counter-example, I excluded the test if (_lockValue) return; and got the following output:
a.out: main.cpp:18: void Lock::lock(): Assertion `!_lock' failed.
Object obj;
obj.value(): 0
obj.sigValueSet = [&](){ obj.setValue(obj.value()); };
obj.setValue(true);
bash: line 7: 12214 Aborted (core dumped) ./a.out
Live Demo on coliru
This is similar to what happened in OPs case with the only difference that in my case double-locking just violated the assert().
To make this complete, I exluded the lock guard std::lock_guard<Lock> lock(_lockValue); as well and got the following output:
execution expired
Live Demo on coliru
The execution was trapped into an infinite recursion, and the online compiler aborted this after a certain time. (Sorry, coliru. I won't do it again.)

Related

How to continue after signal emission?

I'm building a Othello game in Qt quick and C++.
I use this code from QML dialog to start new game, when one player is human, I wait for input. When two players are PC, I face the problem that the GUI will wait for the slot to finish, in PC players the slot call flipTurn() (because it is PC, no input to wait for), flipTurn is recursive, so the GUI will block until the game end.
I want it to update the board after each move. link for the project:
reversi project
myBroker.createGame(blacktypebutton.checkedButton.playertype,
whitetypebutton.checkedButton.playertype,
getBlackAlgo(),
getWhiteAlgo(),
getBlackDep(),
getWhiteDep());
console.log("finished creating game !");
void Broker::flipTurn()
{
if(someoneWon()){
emit gameEnd();
return;
}
emit updateBoard();
if (currentGame->getTurn() == Constants::BLACK){
currentGame->setTurn(Constants::WHITE);
if (currentGame->getWhitePlayer().getType() == Constants::PC){
currentGame->pcMove(Constants::WHITE);
flipTurn();
}
else
currentGame->updatePossible();
}
else{
currentGame->setTurn(Constants::BLACK);
if (currentGame->getBlackPlayer().getType() == Constants::PC){
currentGame->pcMove(Constants::BLACK);
flipTurn();
}
else
currentGame->updatePossible();
return;
}
emit updateBoard();
}
bool Broker::createGame(int blacktype, int whitetype, int blackalg, int whitealg, int blackdep, int whitedep)
{
currentGame = new Game(blacktype,whitetype,blackalg,whitealg,blackdep,whitedep);
currentGame->setGameBoard(&gameBoard);
updatePossible();
emit gameStart();
}
void Broker::onGameStart()
{
if(currentGame->getTurnType() == Constants::PC){
currentGame->pcMove(currentGame->getTurn());
cout<<"in ongamestart slot"<<endl;
flipTurn();
}
}
Since it is a turn based game, you will just need a different source to trigger the next turn.
Instead of calling flipTurn() directly, you call it through Qt's event loop.
Since you probably will want the human in front of the computer to see the game progressing, very likely with a delay.
For example with a single shot timer
// instead of calling flipTurn() directly
QTimer::singleShot(500, this, SLOT(flipTurn()));
Call next flipTurn() after 500 milliseconds.
I used
QCoreApplication::processEvents();
After each call to flipTurn() , so the GUI engine process any waiting signals (in my case the updateBoard() signal).
Although it isn't the best solution, it worked well for my homework.

Memory leak, Pointer changing reference

I'm writing some signal processing routine, using the PortAudio library. I'm using a
stucture which contains a pointer to float which is intended to be used as a buffer. I then pass it to an audio callback function.
My problem is that after callback processing is finished, my pointer has changed reference and thus cannot be freed. This is not such a big deal but the thing is that I don't understand when and how the pointer reference is changed and I'm getting a feel like I'm missing something important.
Here is a simplified version of the code :
typedef struct{
float* tmp;
//other stuff
} Data;
Data data;
data.tmp = NULL;
data.tmp = (float*) calloc(N,sizeof(float));// N is the size of the buffer
Pa_OpenDefaultStream(some args, //opens a PortAudio stream and passes tmp to callback
callback,
&data );
A stream is then started in another high priority thread and the callback is being executed as many times as needed. During callback tmp is being used as a ring buffer and is constantly being copied new data to.
static int callback(args,void* data){
Data* x = (Data*) tmp;
x->tmp = update();
}
where update() returns a pointer to a float which is initialized the same way as tmp is (calloc).
float* update(){
//do stuff
return m_tmp2;
}
float* m_tmp2 = (float*) calloc(N,sizeof(float));//same N as before
But after the stream is closed I get an error when calling free before quitting.
free(data.tmp);//throws a SIGABRT error
Some breakpoint debugging showed me that the reference of the pointer is being changed during the callback processing, but I don't get when and how it happens because everything else runs smoothly. It must be something during the callback execution, but I'm sure update() returns a pointer that is the same size as tmp. Or is it link with PortAudio ?
Please, any clues ?
Not really sure if I understand it right. You allocated the float (x.tmp) every time the callback function is called..
static int callback(args,void* data){
Data* x = (Data*) tmp;
x->tmp = update();
}
I assume the above is typo, you actually mean
static int callback(args,void* data){
Data* x = (Data*) data;
x->tmp = update();
}
Well, you're actually change the pointer value of tmp by assigning it update() because it's reallocate a new memory location in heap and changed the pointing location of the tmp..
float* update(){
//do stuff
return m_tmp2;
}
The data.tmp must have pointed to a new location every time the callback function is called.. So, I don't see why it doesn't behave as you described..
That's the correct behavior already.. Maybe I miss anything?
and maybe you should provide a mechanism to keep track of the buffer.. so all tmp (float *) you allocate for your circular buffer can be freed (not just the first one before the first callback is called..

QProcess dies for no obvious reason

While coding a seemingly simple part of a Qt application that would run a subprocess and read data from its standard output, I have stumbled upon a problem that has me really puzzled. The application should read blocks of data (raw video frames) from the subprocess and process them as they arrive:
start a QProcess
gather data until there is enough for one frame
process the frame
return to step 2
The idea was to implement the processing loop using signals and slots – this might look silly in the simple, stripped-down example that I provide below, but seemed entirely reasonable within the framework of the original application. So here we go:
app::app() {
process.start("cat /dev/zero");
buffer = new char[frameLength];
connect(this, SIGNAL(wantNewFrame()), SLOT(readFrame()), Qt::QueuedConnection);
connect(this, SIGNAL(frameReady()), SLOT(frameHandler()), Qt::QueuedConnection);
emit wantNewFrame();
}
I start here a trivial process (cat /dev/zero) so that we can be confident that it will not run out of data. I also make two connections: one starts the reading when a frame is needed and the other calls a data handling function upon the arrival of a frame. Note that this trivial example runs in a single thread so the connections are made to be of the queued type to avoid infinite recursion. The wantNewFrame() signal initiates the acquisition of the first frame; it gets handled when the control returns to the event loop.
bool app::readFrame() {
qint64 bytesNeeded = frameLength;
qint64 bytesRead = 0;
char* ptr = buffer;
while (bytesNeeded > 0) {
process.waitForReadyRead();
bytesRead = process.read(ptr, bytesNeeded);
if (bytesRead == -1) {
qDebug() << "process state" << process.state();
qDebug() << "process error" << process.error();
qDebug() << "QIODevice error" << process.errorString();
QCoreApplication::quit();
break;
}
ptr += bytesRead;
bytesNeeded -= bytesRead;
}
if (bytesNeeded == 0) {
emit frameReady();
return true;
} else
return false;
}
Reading the frame: basically, I just stuff the data into a buffer as it arrives. The frameReady() signal at the end announces that the frame is ready and in turn causes the data handling function to run.
void app::frameHandler() {
static qint64 frameno = 0;
qDebug() << "frame" << frameno++;
emit wantNewFrame();
}
A trivial data processor: it just counts the frames. When it is done, it emits wantNewFrame() to start the reading cycle anew.
This is it. For completeness, I'll also post the header file and main() here.
app.h:
#include <QDebug>
#include <QCoreApplication>
#include <QProcess>
class app : public QObject
{
Q_OBJECT
public:
app();
~app() { delete[] buffer; }
signals:
void wantNewFrame();
void frameReady();
public slots:
bool readFrame();
void frameHandler();
private:
static const quint64 frameLength = 614400;
QProcess process;
char* buffer;
};
main.cpp:
#include "app.h"
int main(int argc, char** argv)
{
QCoreApplication coreapp(argc, argv);
app foo;
return coreapp.exec();
}
And now for the bizarre part. This program processes a random number of frames just fine (I've seen anything from fifteen to more than thousand) but eventually stops and complains that the QProcess had crashed:
$ ./app
frame 1
...
frame 245
frame 246
frame 247
process state 0
process error 1
QIODevice error "Process crashed"
Process state 0 means "not running" and process error 1 means "crashed". I investigated into it and found out that the child process receives a SIGPIPE – i.e., the parent had closed the pipe on it. But I have absolutely no idea of where and why this happens. Does anybody else?
The code is a bit weird looking (not using the readyRead signal and instead relying on delayed signals/slots). As you pointed out in the discussion, you've already seen the thread on the qt-interest ML where I asked about a similar problem. I've just realized that I, too, used the QueuedConnection at that time. I cannot explain why it is wrong -- the queued signals "should work", in my opinion. A blind shot is that the invokeMethod which is used by the Qt's implementation somehow races with your signal delivery so that you empty your read buffer before Qt gets a chance to process the data. This would mean that Qt will ultimately read zero bytes and (correctly) interpret that as an EOF, closing the pipe.
I cannot find the referenced "Qt task 217111" anymore, but there is a couple of reports in their Jira about waitForReadyRead not working as users expect, see e.g. QTBUG-9529.
I'd bring this to the Qt's "interest" mailing list anmd stay clear of the waitFor... family of methods. I agree that their documentation deserves updating.

Why QProcess signal readyReadStandardOutput() emited twice?

I use QProcess and connect it's readyReadStandardOutput to slot. But after starting slot execute twice. Tell me please why is it?
{
myProcess = new QProcess(parent);
myProcess->start("mayabatch.exe -file "+scene);
connect(myProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readOutput()));
}
void MainWindow::readOutput()
{
qDebug()<<"Read";
QByteArray outData = myProcess->readAllStandardOutput();
qDebug()<<QString(outData);
}
OUTPUT:
Read
"File read in 0 seconds.
"
Read
"cacheFi"
Read
"le -attachFile -fileName "nClothShape1" -directory ...
Last string was broken. "Read" appears between words.
From the documentation of QProcess::readyReadStandardOutput()
This signal is emitted when the process has made new data available through its standard output channel (stdout). It is emitted regardless of the current read channel.
The slot is executed more than once for the simple reason that the underlying process flushed the output in separate and random ways. You should not be caring about this because it depends on things you cannot control.
If you want to save the whole output you should be doing
void MainWindow::readOutput(){
bigbuffer.append(myProcess->readAllStandardOutput();)
}
If you want to read line by line, then
void MainWindow::readOutput(){
while(myProcess.canReadLine()){
qDebug() << myProcess.readLine();
}
}
The second call will leave data in the process buffer such that you don't have "broken" reads like cacheFi.

Why does my program halt when calling front() on a std::queue?

I want to use the Irrnet network library in an Irrlicht game.
The source code uses Linux sockets and I'm trying to port it for Windows replacing it with code that uses Windows' Winsock2.
The library compiles successfully but when I try to run the Quake example it crashes. I located the line at which the program stops but i can't figure out how to solve the problem.
The program stops at the second call of the function getNextItem
class NetworkType {
public :
NetworkType();
~NetworkType();
template<class T>
void getNextItem(irr::core::vector3d<T>& data);
private:
typedef std::queue<std::string> Container;
Container items;
};
template<class T>
void NetworkType::getNextItem(irr::core::vector3d<T>& data) {
T X, Y, Z;
std::istringstream item(items.front());
// the program does not get here the second time it calls this function
items.pop();
item >> X;
item >> Y;
item >> Z;
data = irr::core::vector3d<T>(X, Y, Z);
}
and exactly at this line
std::istringstream item(items.front());
Can anyone tell me why does the program stop the second time it gets to this line ?
here is the link for the complete source code
I assume by "stops" you mean "crashes" in some fashion? Likely causes for a crash on the line in question are:
The NetworkType instance that is invoking the getNextItem() method is garbage (the this pointer is garbage or null). This could happen due to bad pointer math elsewhere, a premature delete or destruction of the instance, et cetera. This would manifest as a fault when the program attempted to access the items member.
The items container is empty. In these cases the return value of front() is undefined (since it is a reference) and the constructor for istringstream may be crashing. front() itself may be raising a debug/runtime check error as well depending on your compiler and its configuration.
Actually you might have a runtime error on this one if the dequeue is empty: MSDN deque
So just check the deque isn't empty before you try to pop a value from it.
if(items.size()>0)
{
//do things
}
else
{
//error deque empty
}
[edit] confounded std and (I guess) MSDN ( OP doesn't say) lib.

Resources