首页 > 解决方案 > 多线程代码中是否有必要使用原子标志?

问题描述

我想知道是否真的有必要在多线程代码中使用原子标志。对于这个问题,我关注多线程代码中的一个常见情况:通过设置标志来停止线程。

让我们假设以下伪代码:

is_running = 1;
create_threads(stopper_thread, running_thread_A, running_thread_B, running_thread_C);


stopper_thread         running_thread_A        running_thread_B        running_thread_C
-------------------------------------------------------------------------------------------
 if (x)             |  while(is_running) {   | while(is_running) {   | while(is_running) {
    is_running = 0; |  }                     | }                     | }

在这个伪代码中,所有running_thread_x线程都使用公共变量is_running来检查它们是否正在运行。当我们想阻止他们时stopper_thread,我们只是设置is_running0。这意味着这is_running是线程之间的共享资源。在许多编码示例中,人们使用原子变量(例如std::atomic_flag在 C++ 中)来is_running标记或访问临界区中的该变量,以在访问该变量时提供互斥。

但是同步这个标志有必要吗?

我以某种方式相信,在类似于上述示例的情况下,仅作为单个或多个停止线程停止操作,实际上没有必要同步对该标志的访问。

为什么?

因为据我所知,即使我们is_running在要停止线程时可以同时访问多个线程中的标志,这种访问也不会阻止通过停止线程设置10标志。发生的情况是,这种变化可能不会立即反映在正在运行的线程中。但这重要吗?我认为不会,因为如果我们不0is_running当前正在运行的线程迭代中读取值,您最终会在多次迭代后读取它,并且线程最终将停止。所以设置这个标志最终会停止所有正在运行的线程,但停止可能会延迟一点。

你怎么看我的论点?我的论点正确吗?或者我可能错过了我的论点失败的情况?

标签: multithreading

解决方案


std::mutex/pthread_mutex_tstd::condition_variable/pthread_cond_t用于与线程通信时,标志不应该是原子的,因为它必须仅在互斥锁被锁定时存储和加载。尝试使用std::atomic//为标志绕过互斥锁会导致死锁atomic_flagatomic_bool

例如:

+-----+--------------------------------+--------------------------------+
|Step |Thread A                        |Thread B                        |
+-----+--------------------------------+--------------------------------+
|1    |                                |lock the mutex                  |
+-----+--------------------------------+--------------------------------+
|2    |                                |check whether the flag is not   |
|     |                                |set or the queue is empty       |
+-----+--------------------------------+--------------------------------+
|3    |set the atomic flag             |                                |
+-----+--------------------------------+--------------------------------+
|4    |notify condition variable       |<notification is lost>          |
+-----+--------------------------------+--------------------------------+
|5    |                                |and if so wait on the condition |
|     |                                |variable.                       |
+-----+--------------------------------+--------------------------------+

在这种情况下,线程 A 可以在 B 完成步骤 2 之后但在完成步骤 5 之前执行步骤 3 和 4。在这种情况下,来自步骤 4 的条件变量通知丢失,导致线程 B 永远等待步骤 5 中的条件变量。


推荐阅读