Qt - 关闭被系统级调用阻止的QThread

时间:2012-11-29 07:30:54

标签: multithreading qt blocking system-calls

我有一个阻塞的线程,直到从USB设备等系统资源接收数据。我选择此模型是因为数据量可能会有所不同,并且可能会随时接收数据。退出应用程序后,我收到消息“ QThread:在线程仍在运行时被销毁”。我应该如何关闭这些线程?

我已经看过其他问题/解决方案,例如:

第一个解决方案涉及使用标志(包含在我的代码中)但是我的线程永远不会到达标志检查。 第二种解决方案使用QWaitCondition,但似乎与第一种解决方案相同。

我在下面列出了代码的精简版本。系统调用WaitForSingleObject()代替我实际使用的东西(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

1 个答案:

答案 0 :(得分:-1)

对于Linux:

使用pthread_kill()向线程发送信号,使用失败代码EINTR中断read()。 sigaction()用于注册信号,抛出的信号是SIGUSR1。

// 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);

适用于Windows:

使用SetEvent()发出OVERLAPPED的hEvent信号,用于取消阻止GetOverlappedResult()。

// Store a reference to the event
HANDLE myEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

...

// Within the start of the thread
OVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(overlapped));
overlapped.hEvent = myEvent;

...

// When it's time to close the thread
SetEvent(myEvent);