Solved QWaitCondition causes app the crash
-
Hi guys,
I have been experimenting with QWaitCondition. The app crashes upon launching.
This is a 2 thread program where 1 thread is allocated for transmitter and the other for receiver.
The error message: The program has unexpectedly finished.
Transmitter:
mutex->lock(); qDebug() << "Initiate 3 way handshake"; sReady->wakeAll(); qDebug() << "Transmitter: Ready"; mutex->unlock();
Receiver:
mutex->lock(); qDebug() << "Receiver"; sReady->wait(mutex); qDebug() << "wake"; mutex->unlock();
Thank you very much :)
-
Use a debugger, I would guess mutex is not initialized.
-
Hi, I have run with debugger, it says Segmentation fault.
Is there a particular reason why? Because what I did was just ask the thread to wait and wake up.
-
@Steve_Lim said in QWaitCondition causes app the crash:
it says Segmentation fault
Where exactly? Which line in your code?
-
@jsulm This is the pop up error message:
The inferior stopped because it received a signal from the operating system.
Signal name :
SIGSEGV
Signal meaning :
Segmentation faultAt below debugger, where the header are level and function:
1)QWaitCondition::WakeAll()
2) ??
3) ??
4) QMetaCallEvent::placeMetaCall(QObject*)
...I hope this is what you are looking for. I am new to all these stuff, apologise if its not useful
-
@Steve_Lim
We really need see the stack trace higher up then you show: can you expand what you show as the...
at the end, such that eventually it shows some line/function in your own code where this is being called from?Meanwhile, from what I see I suspect this is being called from your transmitter's
sReady->wakeAll();
statement. IssReady
valid at this point? You need to ensure that it is a validQWaitCondition
, e.g. it must not have been deleted or gone out of scope. -
@JonB This is the full lines:
- QWaitCondition::wakeAll()
- ??
- ??
- QMetaCallEvent::placeMetaCall(QObject *)
- QObject::event(QEvent *)
- QApplicationPrivate::notify_helper(QObject *, QEvent *)
- QApplication::notify(QObject *, QEvent *)
- QCoreApplication::notifyInternal2(QObject *, QEvent *)
- QCoreApplicationPrivate::sendPostedEvents(QObject *, int, QThreaD...
... QEventDispatcherWin32::processEvents(QFlags<QEventLoop::Process...
...QEventLoop::exec(QFlagQEventLoop::ProcessEventsFlag)
...QThread::run()
...QThreadPrivate::start(void *)
... KERNEL32!BaseThreadInitThunk
... ntdll!RtlUserThreadStart
... ??
I think it would be best to let me explain how I pass the variables, to see if I made any mistake there.
So, there are 3 files, one for main.cpp, the others are transmit.cpp and receiver.cpp.
This is part of the code in my file:
main.cpp:QWaitCondition *sendState; // transmitter state QWaitCondition *receiveState; // receiver state int main(int argc, char *argv[]) { QThread transmitThread; QThread receiveThread; QMutex mutex; transmit *transmitter = new transmit(); receiver *receive = new receiver(); // move each object to their threads transmitter->moveToThread(&transmitThread); receive->moveToThread(&receiveThread); transmitter->init(sendState, receiveState, &mutex); receive->init(sendState, receiveState, &mutex,); transmitThread.start(); receiveThread.start(); }
Transmitter:
void transmit::init( QWaitCondition *sendPin, QWaitCondition *receivePin, QMutex *mtx) { // All has been declared at .h to be pointer eg: QMutex *mutex sent = sendPin; // sent state from transmitter receive = receivePin; // receive state from receiver mutex = mtx; // mutex from main } // Follow with what is posted originally inside another function
Receiver:
Same as transmiter::init, and the other function was what posted originallyHope this helps, thank you.
-
@Steve_Lim
As stated earlier, I see no evidence from this code thatQWaitCondition *sendState
orQWaitCondition *receiveState
are ever set to anyQWaitCondition
. Which would makesReady->wakeAll();
a call on an uninitializedQWaitCondition
. -
@JonB Oh my...., that feels like a rookie mistake. Making QWaitCondition sendState = new QWaitCondition() solves all the issues.
Thank you very much
-
I am not entirely sure what exactly happens in your little main function. However, I suspect there might be lurking some more trouble. First of all, you have 3 threads in total: Every application has a single thread when it starts and you are adding two more. I don't see your application waiting at the end of
main
. Does anyone know if the destructor ofQThread
will be blocking? Otherwise your program will exit right after callingreceiveThread.start()
calling the destructors oftransmitThread
,receiveThread
andmutex
as these are all on the stack.I hope this is just a small reduced example of your real software and does not reflect what you are planning to do.
-
@SimonSchroeder At the end of the main.cpp I have these few lines. Not sure if this is the correct way to quit thread and mutex.
transmitThread.quit(); transmitThread.terminate(); receiveThread.quit(); receiveThread.terminate(); mutex.~QMutex();
-
@Steve_Lim A
QThread
starts an internal event loop. Callingquit()
on it enqueues a signal to that queue to stop the thread. If you don't have a slot running inside the event queue of the thread (a lot of people will write an infinite loop to run in that thread) then the quit request will be handled eventually. Callingterminate()
on the thread is not such a good idea, though. It will kill the thread as fast as possible interrupting any work it was doing. This might leave some shared variables in an undefined state. Only useterminate()
if there is no other way (and your really don't need it here). Instead you should callwait()
on the thread to wait until it has actually finished (as you have calledquit()
before).Finally,
mutex
is a local variable. Its destructor will be called when it goes out of scope. As you call it explicitly it will be called twice. This is a really bad idea. As a general rule of thumb you never call the destructor explicitly (one rare exception is when you write your own vector class managing objects). For stack variables the destructor gets called when the variable goes out of scope and for heap variables (hopefully allocated withnew
) the destructor gets call automatically whendelete
is called.Here is how I would write the last lines of main:
transmitThread.quit(); receiveThread.quit(); transmitThread.wait(); receiveThread.wait();
-
@SimonSchroeder Thank you for the explaination. I did inside my transmitter and receiver class create another function that is called when a window is closed.
Since the receiver keeps on running and never stop, I figure it is a good idea to put an if statement where when the window is closed, it will stop the receiver from running for another time.