我在下面的程式中錯過了什么,執行緒等待condition_variable_any確定何時停止?在下面列出的程式中,執行緒以不可預知的方式停止;有些在呼叫之前notify_all,有些根本不停止。
使用的條件變數定義如下:
static std::mutex interrupt_mutex;
static std::condition_variable_any interrupt_cv;
執行緒檢查是否該停止如下:
std::unique_lock<std::mutex> lock(interrupt_mutex);
const auto cv_status = interrupt_cv.wait_for(lock, std::chrono::milliseconds(1000));
const auto timeout_expired = cv_status == std::cv_status::timeout;
if (!timeout_expired)
{
quit = true;
}
主執行緒發出信號停止執行緒,如下所示:
std::unique_lock<std::mutex> lock(interrupt_mutex);
interrupt_cv.notify_all();
可能的輸出如下所示:
Thread 1> Received interrupt signal at iteration 2
Thread 1> Terminate
Thread 2> Received interrupt signal at iteration 2
Thread 2> Terminate
Thread 4> Received interrupt signal at iteration 2
Thread 4> Terminate
**** Requesting all threads to stop ****
Waiting for all threads to complete...
在重現問題的完整代碼下方:
#include <thread>
#include <vector>
#include <mutex>
#include <condition_variable>
static std::mutex interrupt_mutex;
static std::condition_variable_any interrupt_cv;
int main()
{
std::vector<std::thread> thread_handles;
for (int thread_idx = 0; thread_idx < 4; thread_idx)
{
thread_handles.emplace_back(std::thread([thread_idx](const int thread_id)
{
int num_iterations = 0;
auto quit = false;
while (!quit)
{
// Fake processing time during the lock for testing purpose
std::this_thread::sleep_for(std::chrono::milliseconds(200));
num_iterations;
// Check if need to stop with a timeout of 200ms
{
std::unique_lock<std::mutex> lock(interrupt_mutex);
const auto cv_status = interrupt_cv.wait_for(lock, std::chrono::milliseconds(1000));
if (const auto timeout_expired = cv_status == std::cv_status::timeout; !timeout_expired)
{
printf("Thread -> Received interrupt signal at iteration %d\n", thread_id, num_iterations);
quit = true;
}
}
}
printf("Thread -> Terminate\n", thread_id);
}, thread_idx 1));
}
std::this_thread::sleep_for(std::chrono::seconds(5));
// Signals all threads to stop
{
printf("**** Requesting all threads to stop ****\n");
std::unique_lock<std::mutex> lock(interrupt_mutex);
interrupt_cv.notify_all();
}
// Wait until all threads stop
printf("Waiting for all threads to complete...\n");
std::ranges::for_each(thread_handles, [](std::thread& thread_handle)
{
thread_handle.join();
});
printf("Program ends\n");
return 0;
}
uj5u.com熱心網友回復:
A用于在條件更改時(例如,當共享變數更改值時)condition_variable向執行緒發出信號。但是您的代碼沒有條件。您正在嘗試將其本身用作退出信號,這不是它的意思。 只會喚醒在那一刻積極等待的執行緒。沒有等待它的執行緒,因為它們正忙于做其他事情,將不會收到終止的信號。但是這些執行緒一旦準備好等待就需要檢測條件。所以條件需要更持久。這就是您的代碼無法正常作業的原因。condition_variablenotify_all()condition_variable
在這種情況下,您可以簡單地將變數移動到全域范圍,在andquit旁邊。設定該變數將作為您可以發出等待執行緒信號的條件。然后,您可以使用它的多載版本,讓您檢查當前狀態(忽略虛假喚醒)。condition_variablemutexquitwait_for()quit
嘗試更多類似的東西:
#include <thread>
#include <vector>
#include <mutex>
#include <condition_variable>
static std::mutex interrupt_mutex;
static std::condition_variable_any interrupt_cv;
static bool quit = false;
int main()
{
std::vector<std::thread> thread_handles;
for (int thread_idx = 0; thread_idx < 4; thread_idx)
{
thread_handles.emplace_back(std::thread([thread_idx](const int thread_id)
{
int num_iterations = 0;
while (true)
{
// Fake processing time outside the lock for testing purpose
std::this_thread::sleep_for(std::chrono::milliseconds(200));
num_iterations;
// Check if need to stop with a timeout of 1s
{
std::unique_lock<std::mutex> lock(interrupt_mutex);
const bool signaled = interrupt_cv.wait_for(lock, std::chrono::seconds(1), [](){ return quit; });
if (signaled) break;
}
}
printf("Thread -> Received interrupt signal at iteration %d\n", thread_id, num_iterations);
printf("Thread -> Terminate\n", thread_id);
}, thread_idx 1));
}
std::this_thread::sleep_for(std::chrono::seconds(5));
// Signals all threads to stop
printf("**** Requesting all threads to stop ****\n");
{
std::lock_guard<std::mutex> lock(interrupt_mutex);
quit = true;
}
interrupt_cv.notify_all();
// Wait until all threads stop
printf("Waiting for all threads to complete...\n");
std::ranges::for_each(thread_handles, [](std::thread& thread_handle)
{
thread_handle.join();
});
printf("Program ends\n");
return 0;
}
uj5u.com熱心網友回復:
您的代碼有 2 個問題,并且都有相同的解決方案。
- 虛假喚醒。如果你
wait_for是因為 SW 而結束,你會滿足你的條件,盡管實際上沒有人要求它喚醒/結束。 - 如果你的執行緒沒有持有鎖并且沒有休眠并且你的主執行緒通知了所有人怎么辦?請注意,通知不會存盤在任何地方,因此如果您錯過了通知,以后將不會收到通知。所以那些錯過的執行緒永遠不會終止。
要解決這兩個問題,您需要另一個標志,它會告訴您的執行緒作業已完成并且它們必須停止。
static bool stop = false;
//...
if (stop) // Instead of if (const auto timeout_expired = cv_status == std::cv_status::timeout; !timeout_expired)
//...
printf("**** Requesting all threads to stop ****\n");
std::unique_lock<std::mutex> lock(interrupt_mutex);
stop = true;
interrupt_cv.notify_all();
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/452676.html
