2012-11-29 64 views
3

我有一個線程阻塞,直到從系統資源(如USB設備)接收數據。我選擇這個模型是因爲數據量可能會有所不同,並且可能隨時收到數據。在退出應用程序時,我收到消息「QThread:線程仍在運行時銷燬」。我應該如何去關閉這些線程?Qt - 系統級調用阻塞的QThreads

我看了其他問題/解決方案,如:

第一個解決方案包括使用標誌(包括在我的代碼),但是我的線程將從來沒有達到國旗檢查。 第二個解決方案使用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 
+2

爲什麼不使用Qt自己的IO函數,如QFile等?他們使用信號和插槽,所以你只能看'bytesReadyRead'信號。 – sashoalm

+0

@satuon我正在製作我自己的QIODevice,它可以讀寫HID設備。雖然這在我以前從未發生過,但也許可以使用QFile來訪問這些設備。我會試試看,謝謝。 – Daniel

+1

順便說一句,你可以通過縮短和簡化來改善你的問題 - 我讀了不到10%,因爲它太長了。你也應該只發布代碼的相關部分,而不是整個文件。 – sashoalm

回答

-1

對於Linux:

將信號發送到與pthread_kill()線程打斷讀()與失敗代碼EINTR。 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的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); 
+1

Downvoted without comment。我如何改進答案? – Daniel

+1

您的答案在功能上與QThread對象已提供的quit(),terminate()和exit()調用相同,除了您選擇了不同的信號發送。你的「解決方案」不會導致錯誤的原因是你添加了一個表達式信號處理程序。從理論上講,你也可以在你的QThread中加入一個通用的信號處理程序,它將以同樣的方式解決問題。 (我不是downvote) – mtalexan