[Solved] How to close threads that are blocked by system-level calls?



  • I have a thread which blocks until data is received from a system resources such as a USB device. I chose this model because the amount of data may vary, and data may be received at any time. Upon exiting the application, I get the message "QThread: Destroyed while thread is still running". How should I go about closing these threads?

    I've looked at other problems/solutions such as:
    http://www.qtcentre.org/threads/14429-Loop-inside-Qthread-causes-quot-QThread-Destroyed-while-thread-is-still-running-quot
    http://www.qtcentre.org/threads/6211-QThread-Destroyed-while-thread-is-still-running
    The first solution involves using a flag (included in my code) however my thread will never reach the flag check.
    The second solution uses QWaitCondition but seem to be along the same lines as the first.

    I’ve included a stripped down version of the code below. The system calls WaitForSingleObject() is a substitute for what I actually use (GetOverlappedResult()).
    @#ifndef CONTROLLER_H
    #define CONTROLLER_H

    #include <QObject>
    #include <QThread>
    #include <QReadWriteLock>
    #include <QDebug>

    #ifdef Q_OS_WIN
    #include <windows.h>
    #endif // Q_OS_WIN

    #ifdef Q_OS_LINUX
    #include <unistd.h>
    #endif // Q_OS_LINUX

    ////////////////////////////////////////////////
    //
    // Worker Object
    //
    ////////////////////////////////////////////////
    class Worker : public QObject {
    Q_OBJECT

    public:
    QReadWriteLock lock;
    bool running;

    public slots:
    void loop() {
    qDebug() << "entering the loop";
    bool _running;
    forever {

            lock.lockForRead();
            _running = running;
            lock.unlock();
    
            if (!_running) return;
    
            qDebug() << "loop iteration";
    
            #ifdef Q_OS_WIN
                HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
                WaitForSingleObject(event, INFINITE);
            #endif // Q_OS_WIN
    
            #ifdef Q_OS_LINUX
                read(0, 0, 1);
            #endif // Q_OS_LINUX
        }
    }
    

    };

    ////////////////////////////////////////////////
    //
    // Controller
    //
    ////////////////////////////////////////////////
    class Controller {
    public:
    Controller() {
    myWorker.connect(&myThread, SIGNAL(started()), &myWorker, SLOT(loop()));
    myWorker.moveToThread(&myThread);
    myThread.start();
    }

    ~Controller() {
        // Safely close threads
    
        myWorker.lock.lockForWrite();
        myWorker.running = false;
        myWorker.lock.unlock();
    
        myThread.quit();
    
        //myThread.wait();
        //myThread.exit();
        //myThread.terminate();
    }
    

    private:
    QThread myThread;
    Worker myWorker;
    };

    #endif // CONTROLLER_H
    @



  • Solved.

    On linux, sending a signal to the thread will make read() fail with EINTR. To send the signal I used "sigaction":http://linux.die.net/man/3/sigaction:

    @// Global scope
    void nothing(int signum) {}

    ...

    // Within the start of the thread
    pthread_t myThreadID = pthread_self(); // Get the thread ID
    struct sigaction action;
    action.sa_flags = 0;
    sigemptyset(&action.sa_mask);
    action.sa_handler = nothing;
    sigaction(SIGUSR1, &action, NULL);

    ...

    // When it's time to close the thread
    pthread_kill(myThreadID, SIGUSR1);
    @

    For windows, I believe I can achieve the same effect if I signal the event within the OVERLAPPED structure.



  • For windows, my thread blocked at GetOverlappedResults(). I stored a HANDLE to an event I created with HANDLE myEvent = CreateEvent(NULL, FALSE, FALSE, NULL); and set the OVERLAPPED's hEvent member to myEvent. To unblock it, I signalled the event with SetEvent(myEvent).

    GetOverlappedResults() http://msdn.microsoft.com/en-us/library/windows/desktop/ms683209(v=vs.85).aspx
    CreateEvent() http://msdn.microsoft.com/en-us/library/windows/desktop/ms682396(v=vs.85).aspx
    SetEvent() http://msdn.microsoft.com/en-us/library/windows/desktop/ms686211(v=vs.85).aspx


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.