簡體   English   中英

C ++:如何在UI線程和工作程序std :: thread之間使用std :: condition_variable

[英]C++ : How to use an std::condition_variable between UI thread & worker std::thread

我正在嘗試使用C++11std :: condition_variable進行UI線程和工作線程之間的數據事務。

情況:
m_calculated_value是在復雜邏輯之后計算的值。 UI線程觸發事件時需要這樣做。 UI線程調用MyClass::GetCalculatedValue獲取的價值m_calculated_value需要由工作線程函數,計算MyClass::ThreadFunctionToCalculateValue

碼:

std::mutex              m_mutex;
std::condition_variable m_my_condition_variable;
bool                    m_value_ready;
unsigned int            m_calculated_value;


// Gets called from UI thread
unsigned int MyClass::GetCalculatedValue() {

    std::unique_lock<std::mutex> lock(m_mutex);
    m_value_ready = false;

    m_my_condition_variable.wait(lock, std::bind(&MyClass::IsValueReady, this));

    return m_calculated_value;
}


bool MyClass::IsValueReady() {

    return m_value_ready;
}

// Gets called from an std::thread or worker thread
void MyClass::ThreadFunctionToCalculateValue() {

    std::unique_lock<std::mutex> lock(m_mutex);

    m_calculated_value = ComplexLogicToCalculateValue();
    m_value_ready = true;

    m_my_condition_variable.notify_one();
}

問題:
但是問題是m_my_condition_variable.wait永遠不會返回。

題:
我在這里做錯了什么?

使UI線程等待來自工作線程的條件變量信號是否正確? 我如何擺脫由於工作線程函數錯誤而導致condition_variable永遠不會觸發的情況? 有什么辦法可以在這里使用超時嗎?

試圖了解其工作原理:
我在許多示例中看​​到,他們使用while循環檢查 condition_var.wait周圍的布爾變量condition_var.wait 變量的循環點是什么? 廣東話我希望 m_my_condition_variable返回出waitnotify_one從其他線程調用?

最有可能發生的事情:您的工作線程擁有並持有該互斥鎖,直到完成計算為止。 主線程必須等待,直到它可以獲取鎖為止。 it releases the lock (in the destructor), by which time no other thread that would want to wait on the condition variable could have been acquired the lock that it still occupied by the notifying thread. 工作者將釋放鎖定 (在析構函數中)向CV發送信號,屆時將沒有其他想要等待條件變量的線程獲得通知線程仍在占用的鎖定。 因此,另一個線程在獲得通知時永遠沒有機會等待條件變量,因為它在通知事件發生后才設法獲取了鎖定,從而導致它無限等待。

解決方案是刪除MyClass :: ThreadFunctionToCalculateValue()中的鎖定獲取,根本不需要,或者至少不需要這樣做。

但是無論如何,為什么要重新發明輪子呢? 對於此類問題,已創建std :: future

auto future = std::async(std::launch::async, ComplexLogicToCalculateValue);
bool is_ready = future.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
auto result = future.get();

在這里,您可以輕松定義超時,而不必擔心condition_variables之類的問題。

不能我希望當從其他線程調用notify_one時m_my_condition_variable返回等待狀態嗎?

,不是唯一的。 仍然可能發生虛假喚醒。

在這里看看這個例子:

http://en.cppreference.com/w/cpp/thread/condition_variable

下面的示例代碼的注釋中指出的對相關代碼的更改。 您可能要考慮使用與cppreference.com示例中使用的“握手”相同的方式來在安全地計算新值(UI線程具有wait / notify,工作線程具有notify / wait)時進行同步。

在條件變量等待之前,需要鎖定該鎖。 等待將解鎖,等待通知,然后鎖定並使用謂詞功能,檢查是否准備就緒,如果尚未准備就緒(偽喚醒),請重復該循環。

在notify_one之前,應先解鎖該鎖,否則將喚醒等待,但無法獲取鎖(因為它仍處於鎖定狀態)。

std::mutex              m_mutex;
std::condition_variable m_my_condition_variable;
bool                    m_value_ready = false;  // init to false
unsigned int            m_calculated_value;


// Gets called from UI thread
unsigned int MyClass::GetCalculatedValue() {
    std::unique_lock<std::mutex> lock(m_mutex);
    m_my_condition_variable.wait(lock, std::bind(&MyClass::IsValueReady, this));
    m_value_ready = false;    // don't change until after wait
    return m_calculated_value;
}  // auto unlock after leaving function scope

bool MyClass::IsValueReady() {

    return m_value_ready;
}

// Gets called from an std::thread or worker thread
void MyClass::ThreadFunctionToCalculateValue() {
    std::unique_lock<std::mutex> lock(m_mutex);
    m_calculated_value = ComplexLogicToCalculateValue();
    m_value_ready = true;
    lock.unlock();         // unlock before notify
    m_my_condition_variable.notify_one();
}

或替代:

// Gets called from an std::thread or worker thread
void MyClass::ThreadFunctionToCalculateValue() {

    {   // auto unlock after leaving block scope
        std::lock_guard<std::mutex> lock(m_mutex);
        m_calculated_value = ComplexLogicToCalculateValue();
        m_value_ready = true;
    }   // unlock occurs here
    m_my_condition_variable.notify_one();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM