2014-12-02 111 views
0

我目前的問題是有兩個QT線程。其中之一發出一個信號在第二個線程中開始一個操作,然後等待結果。一旦第二個線程完成,第一個線程應該繼續使用第二個線程的結果進行自己的操作。解決QT線程運行時問題

爲了讓第一個線程睡眠,我使用QMutex和QWaitCondition。第一個線程發出信號,然後在等待狀態下休眠。但現在的問題是:如果第二個線程設法比第一個線程更快,並且在第一個線程進入等待條件之前發出wakeAll() - 調用,我會卡住。我可以實現一個等待時間,但之後我又不靈活了,如果第二個線程需要比第一個線程等待更多的時間,我再次遇到問題。

這個問題已經在這裏解決:http://woboq.com/blog/qwaitcondition-solving-unavoidable-race.html,但他們決定不解決這個問題。那麼,是否有可能避免這種競爭條件?

此外:我不想將此函數轉換爲第一個線程的函數,因爲此特定函數應該可以從多個線程一次訪問而不會導致競爭條件。即Thread1應該調用Thread2中的函數,等到它完成後,Thread3也想調用該函數,但不允許這樣做,它也必須等到完成。如果功能完成,Thread3可以訪問它。 (同樣不止兩個線程)。

實例功能:
這個功能應該發出信號,之後等待喚醒信號:

void Spectrometer_Control::moveStepper(int steps, bool dir) 
{ 
    emit stepperMoving(); 
    qDebug() << "From Spectrometer_Control: Stepper should move in direction " + QString::number(dir) + " from position " + QString::number(MonoPos); 
    int newTarget = MonoPos + ((dir == true)?(steps):(-1 * steps)); 
    qDebug() << "New target: " + QString::number(newTarget); 
    emit moveStepperToTarget(steps, dir); 
    qDebug() << "Locking WaitMutex!"; 
    WaitMutex->lock(); 
    qDebug() << "Waiting for signal!"; 
    WaitForEngine->wait(WaitMutex); 
    WaitMutex->unlock(); 
    qDebug() << "Finally unlocked!"; 
} 

而這個函數接收呼叫,並且應該喚醒每一個等待功能了:

void Stepper_Control_Worker::moveStepper(int steps, bool dir) 
{ 
    waitMutex->lock(); 
    qDebug() << "Motor moved from down below!"; 
    Stepper_Control_Worker::STP[1]->setValue((dir == true)?BlackLib::high:BlackLib::low); 
    usleep(50000); 
    Stepper_Control_Worker::STP[0]->setValue(BlackLib::low); 
    usleep(50000); 
    for(int i = 0; i < steps; i++) 
    { 
     Stepper_Control_Worker::STP[0]->setValue(BlackLib::high); 
     usleep(50000); 
     Stepper_Control_Worker::STP[0]->setValue(BlackLib::low); 
    } 
    WaitCond->wakeAll(); 
    waitMutex->unlock(); 
    emit StepperMoved(steps, dir); 
} 

第二個函數是類「stepper_control」的子成員(不是直接訪問,但只能通過訪問)。步進控制器外部控制器可以用於多種功能,不僅是Spectrometer_Control的moveStepper功能,而且爲了使事情更簡單,我只添加了一個外部功能。但是在我不想讓我的步進器感到困惑之後,我想按照上面的描述限制訪問。

+0

爲什麼要使用第二個線程,如果你只是想讓第一個線程休眠並等待第二個線程完成? – TheDarkKnight 2014-12-02 11:42:22

+0

因爲我的第二個線程在另一個類中,所以也應該通過其他幾種方式訪問​​它。把它放到這個類的函數中,就不可能從其他線程中的其他線程使用它,這些線程也必須等待它。 (AFAIK,這是錯的)? – 2014-12-02 11:45:54

+1

線程不駐留在類中。 QThread更像是一個線程控制器。派生自QObject的類可以移動到不同的線程。無論如何,我仍然不明白爲什麼你需要創建第二個線程。線程允許併發處理,根據你的描述,你的應用程序沒有使用這個。如果您發佈了問題的示例代碼,您可能會收到更好的回覆,並且缺乏這可能是爲什麼有人(而不是我)決定降低您的問題的原因。 – TheDarkKnight 2014-12-02 13:57:08

回答

2

讓第二個線程發回一個信號並將代碼過帳等待到該插槽可能是安全的。

class Worker1: public QObject{ 
    Q_OBJECT 

    //... 

    signals: 
     void startWorking(); 
    slots: 
     void answer(QVariant); 
}; 

class Worker2: public QObject{ 
    Q_OBJECT 

    //... 

    slots: 
     void startWorking(); 
    signals: 
     void answer(QVariant); 
}; 

否則,你需要有一個變量,第二個線程組,同時保持QMutex信號第一:

線程1:

emit startWorking(); 
{ 
    QMutexLocker lock(&thread2->mutex); 
    while(!thread2->finished){//loop guards against spurious wakeups 
     thread2->cond->wait(&mutex); 
    } 
} 

及線程:

{ 
    QMutexLocker lock(&mutex); 
    finished=true; 
    cond->wakeAll(); 
} 

那樣如果thread2更快然後thread2->finished已經是真的b y thread1到達的時間,互斥量在測試和等待QWaitCondition之間保護變量。

0

也許Qt::BlockingQueuedConnection是你需要什麼?

阻塞排隊連接就像是一個排隊連接,但發送者線程阻塞,直到事件被接收者所在線程的事件循環拾取爲止,該槽被調用並返回;