gpt4 book ai didi

c++ - 用于取消标志的 std::atomic_bool:std::memory_order_relaxed 是正确的内存顺序吗?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:26:22 25 4
gpt4 key购买 nike

我有一个从套接字读取并生成数据的线程。每次操作后,线程都会检查一个 std::atomic_bool 标志以确定它是否必须提前退出。

为了取消操作,我将取消标志设置为true,然后在工作线程对象上调用join()

线程和取消函数的代码如下所示:

std::thread work_thread;
std::atomic_bool cancel_requested{false};

void thread_func()
{
while(! cancel_requested.load(std::memory_order_relaxed))
process_next_element();

}

void cancel()
{
cancel_requested.store(true, std::memory_order_relaxed);
work_thread.join();
}

对于这种原子变量的使用,std::memory_order_relaxed 是正确的内存顺序吗?

最佳答案

只要cancel_requested 标志和任何其他 之间没有依赖关系,您就应该是安全的。

显示的代码看起来不错,假设您使用 cancel_requested 只是为了加快关闭,但也有有序关闭的规定,例如在队列(当然还有队列本身是同步的)。

这意味着您的代码实际上是这样的:

std::thread work_thread;
std::atomic_bool cancel_requested{false};
std::mutex work_queue_mutex;
std::condition_variable work_queue_filled_cond;
std::queue work_queue;

void thread_func()
{
while(! cancel_requested.load(std::memory_order_relaxed))
{
std::unique_lock<std::mutex> lock(work_queue_mutex);
work_queue_filled_cond.wait(lock, []{ return !work_queue.empty(); });
auto element = work_queue.front();
work_queue.pop();
lock.unlock();
if (element == exit_sentinel)
break;
process_next_element(element);
}
}

void cancel()
{
std::unique_lock<std::mutex> lock(work_queue_mutex);
work_queue.push_back(exit_sentinel);
work_queue_filled_cond.notify_one();
lock.unlock();
cancel_requested.store(true, std::memory_order_relaxed);
work_thread.join();
}

如果我们做到了那么远,那么 cancel_requested 也可以成为一个常规变量,代码甚至会变得更简单。

std::thread work_thread;
bool cancel_requested = false;
std::mutex work_queue_mutex;
std::condition_variable work_queue_filled_cond;
std::queue work_queue;

void thread_func()
{
while(true)
{
std::unique_lock<std::mutex> lock(work_queue_mutex);
work_queue_filled_cond.wait(lock, []{ return cancel_requested || !work_queue.empty(); });
if (cancel_requested)
break;
auto element = work_queue.front();
work_queue.pop();
lock.unlock();
process_next_element(element);
}
}

void cancel()
{
std::unique_lock<std::mutex> lock(work_queue_mutex);
cancel_requested = true;
work_queue_filled_cond.notify_one();
lock.unlock();
work_thread.join();
}

memory_order_relaxed 通常很难推理,因为它模糊了顺序执行代码的一般概念。所以它的用处非常非常有限,正如 Herb 在他的 atomic weapons talk 中解释的那样。 .

注意 std::thread::join() 本身充当两个线程之间的内存屏障。

关于c++ - 用于取消标志的 std::atomic_bool:std::memory_order_relaxed 是正确的内存顺序吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53653252/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com