一次停止多个线程
在下面的程序中,当线程等待 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 %2d> Received interrupt signal at iteration %d\n", thread_id, num_iterations);
quit = true;
}
}
}
printf("Thread %2d> 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;
}
What do I miss in the program below with threads waiting for a condition_variable_any
to determine when to stop ? In the program listed below, the threads stop in an impredictable way; some before the call to notify_all
and some don't stop at all.
The condition variable used is defined as below:
static std::mutex interrupt_mutex;
static std::condition_variable_any interrupt_cv;
The threads check if it is time to stop as below:
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;
}
The main thread signals the threads to stop as below:
std::unique_lock<std::mutex> lock(interrupt_mutex);
interrupt_cv.notify_all();
A possible output looks like:
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...
Below the complete code that reproduces the problem:
#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 %2d> Received interrupt signal at iteration %d\n", thread_id, num_iterations);
quit = true;
}
}
}
printf("Thread %2d> 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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
code> condition_variable
是指在条件更改时(例如,当a 共享变量更改值时)发出信号。但是您的代码没有条件。您正在尝试将condition_variable
本身用作退出信号,而这并不是它的目的。notify_all()
只能唤醒在此精确时刻在code> procention_variable
上积极等待的线程。没有等待它的线程,因为他们忙于做其他事情,不会收到该信号以终止。但是,这些线程一旦准备好等待,就需要检测条件。因此,条件需要更持久。这就是为什么您的代码无法正常工作的原因。在这种情况下,您可以简单地将
退出
变量移至全局范围,在code> procention_variable
和mutex
。设置该退出
变量将充当您的条件,您可以向等待线索发出信号。然后,您可以使用wait_for()
的超载版本,该版本可以让您检查退出
的当前状态(忽略虚假觉醒)。尝试更多这样的东西:
A
condition_variable
is meant to signal threads when a condition changes (ie, such as when a shared variable changes value). But your code has no condition. You are trying to use thecondition_variable
itself as a quit signal, and that is not what it is meant for.notify_all()
will only wake up threads that are actively waiting on thecondition_variable
at that exact moment. Threads that are not waiting on it, because they are busy doing something else, will not receive that signal to terminate. But those threads will need to detect the condition once they are ready to wait. So the condition needs to be something more persistent. That is why your code is not working correctly.In this case, you can simply move your
quit
variable to global scope, next to thecondition_variable
andmutex
. Setting thatquit
variable will act as your condition that you can signal waiting threads about. You can then use the overloaded version ofwait_for()
that will let you check the current state ofquit
(to ignore spurious awakenings).Try something more like this:
您的代码有2个问题,并且都具有相同的解决方案。
Wait_for
由于SW而结束,则您的病情会满足您的状况,尽管没有人实际要求它唤醒/结束。为了解决这两个问题,您需要另一个标志,这将告诉您的线程工作已经完成,并且必须停止。
There are 2 issues with your code and both have the same solution.
wait_for
is ended because of SW, you will have your condition satisfied, although no one actually requested it to wake-up/end.To fix both issues you need another flag, which will tell your threads that job is done and they have to stop.