2016-11-08 65 views
0

我使用QSharedMemory和QSystemSemaphore來組織多個進程之間的事件交換。 QSharedMemory存儲接收器和事件數據的數量。接收者正在等待QSystemSemaphore :: acquire()。發件人通過QSystemSemaphore :: release([接收器數量])通知他們。QSystemSemaphore :: acquire()abort

除了在共享內存中引入標誌「真實」/「假」並隨後在終止過程中生成「假」事件之外,是否有任何方法可以正常終止接收過程?

+0

你問題不清楚。你的意思是當你在線程中調用'terminate'時,線程不會終止,並被卡在'QSystemSemaphore :: acquire()'中? – Hayt

+0

這是一個XY問題:您必須讓我們看到森林,而不是單個樹。你到底在做什麼?最有可能的是你的問題有一個更簡單的解決方案 - 無論這個問題是真的。請編輯該問題以闡明您的系統結構,也許會創建一個簡短的測試用例。你可以[從main.cpp'輕鬆啓動多個進程!](http://stackoverflow.com/a/18602568/1329652)。 –

回答

2

QThread::terminate()適用於任何平臺,無論此刻線程在做什麼。當然,如果您在應用程序中終止了任意線程,則唯一可以安全執行的其他操作是調用abort:此時該進程通常處於中斷狀態。 不要做任何事情,除了abort() - 在您撥打QThread::terminate後。由於它具有很強的破壞性,因此您最好不要撥打terminate並直接中止。

在致電terminate後,您的問題就好像您有計劃繼續使用該應用程序一樣。你不能!

唉,如果您只想讓一個線程退出,信號量是一個同步原語,您可以通過設置一個標誌並釋放信號量來輕鬆完成。下面是一個有點人爲的例子,因爲你通常不會這樣使用線程池:它只是縮短代碼。

// https://github.com/KubaO/stackoverflown/tree/master/questions/semaphore-quit-40488523 
#include <QtCore> 

class Worker : public QRunnable { 
    static const QString m_key; 
    static QAtomicInteger<bool> m_abort; 
    void run() override { 
     QSystemSemaphore sem{m_key}; 
     qDebug() << "working"; 
     while (true) { 
      sem.acquire(); 
      if (m_abort.load()) { 
       sem.release(); 
       qDebug() << "aborting"; 
       return; 
      } 
      sem.release(); 
     } 
    } 
public: 
    static void acquire(int n = 1) { 
     QSystemSemaphore sem{m_key}; 
     while (n--) 
      sem.acquire(); 
    } 
    static void release(int n = 1) { 
     QSystemSemaphore{m_key}.release(n); 
    } 
    static void quit(int n) { 
     m_abort.store(true); 
     release(n); 
    } 
}; 
const QString Worker::m_key = QStringLiteral("semaphore-quit-40488523"); 
QAtomicInteger<bool> Worker::m_abort = false; 

int main() 
{ 
    QThreadPool pool; 
    QVarLengthArray<Worker, 20> workers{20}; 
    for (auto & worker : workers) { 
     worker.setAutoDelete(false); 
     pool.start(&worker); 
    } 
    Worker::release(workers.size()); // get some workers churning 
    QThread::sleep(5); 
    Worker::acquire(workers.size()); // pause all the workers 
    Worker::quit(workers.size()); 
    // The thread pool destructor will wait for all workers to quit. 
} 
+0

好吧,我的意思是QThread :: terminate()在QThread :: terminate()之後在Windows上工作(成功完成),但不在Linux上。我同意terminate()是不好的方法,但有什麼選擇?問題不是關於terminate()。它關於如何中斷acquire()。 – groaner

+0

@groaner同樣,'QThread :: terminate'之後你可以做的** only **是'abort()'。它在Windows上工作是一個巧合。它不需要工作,並且不能保證工作,並且在Linux上確實無法工作。另一種方法是釋放信號量......這是你的信號量,對吧?你一定在做些奇怪的事情。顯示你的代碼。 –

+0

這不是我的(過程中)信號量。它是全局(進程間)信號量(QSystemSemaphore,而不是QSemaphore)。我用它將事件從一個進程傳遞到另一個進程。如果我在一個過程中釋放它,它會影響另一個過程,不是嗎? – groaner