Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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 :)


  • Qt Champions 2019

    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.


  • Qt Champions 2019

    @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 fault

    At 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. Is sReady valid at this point? You need to ensure that it is a valid QWaitCondition, e.g. it must not have been deleted or gone out of scope.



  • @JonB This is the full lines:

    1. QWaitCondition::wakeAll()
    2. ??
    3. ??
    4. QMetaCallEvent::placeMetaCall(QObject *)
    5. QObject::event(QEvent *)
    6. QApplicationPrivate::notify_helper(QObject *, QEvent *)
    7. QApplication::notify(QObject *, QEvent *)
    8. QCoreApplication::notifyInternal2(QObject *, QEvent *)
    9. 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 originally

    Hope this helps, thank you.



  • @Steve_Lim
    As stated earlier, I see no evidence from this code that QWaitCondition *sendState or QWaitCondition *receiveState are ever set to any QWaitCondition. Which would make sReady->wakeAll(); a call on an uninitialized QWaitCondition.



  • @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 of QThread will be blocking? Otherwise your program will exit right after calling receiveThread.start() calling the destructors of transmitThread, receiveThread and mutex 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. Calling quit() 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. Calling terminate() 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 use terminate() if there is no other way (and your really don't need it here). Instead you should call wait() on the thread to wait until it has actually finished (as you have called quit() 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 with new) the destructor gets call automatically when delete 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.


Log in to reply