[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_OBJECTpublic:
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