首页 > 解决方案 > 为什么布尔值需要是原子的?

问题描述

在 rust 中,有一个AtomicBool 之类的东西。它被定义为:

可以在线程之间安全共享的布尔类型。

我知道,如果您使用布尔值来实现线程锁,则可以从多个线程中使用来控制对资源的访问,例如:

// Acquire the lock
if thread_lock == false:
    thread_lock = true

...

// Release the lock
thread_lock = false

绝对不是线程安全的。两个线程可以同时读取thread_lock 变量,看到它被解锁(false),设置为true,并且都认为他们对线程有独占访问权。

使用适当的线程锁,您需要一个布尔值,当您尝试设置它时,会发生以下两种情况之一:

我不知道 Rust 是否有这样的概念,但我知道 Pythonthreading.Lock正是这样做的。

据我所知,这不是一个AtomicBool解决方案。一个AtomicBool有一个load()方法,一个store()方法。既不返回Result<bool>类型(暗示操作不会失败),据我所知,也没有任何类型的阻塞。

究竟是什么AtomicBool保护我们?为什么我们不能使用来自不同线程的常规布尔值(除了编译器不允许我们这样做)?

我唯一能想到的是,当一个线程将这些位写入内存时,另一个线程可能会尝试同时读取这些位。布尔值是 8 位。如果在另一个线程尝试读取数据时写入了 8 位中的 4 位,则读取的数据将是旧值的 4 位和新值的 4 位。这是正在解决的问题吗?这会发生吗?即使在这种情况下,bool 似乎也不需要是原子的,因为在 8 位中,只有一位很重要,即 0 或 1。

标签: multithreadingrust

解决方案


AtomicBool 究竟能保护我们免受什么影响?为什么我们不能使用来自不同线程的常规布尔值(除了编译器不允许我们这样做)?

任何可能出错的事情,不管你能不能想到。我讨厌用我能想到的东西来跟进这件事,因为这无关紧要。规则说它不能保证有效,应该结束它。认为你必须想出一种可能失败或不能失败的方法是错误的。

但这是一种方法:

 // Release the lock
 thread_lock = false

假设这个特定的 CPU 没有特别好的方法可以在不使用寄存器的情况下将布尔值设置为 false,但确实有一个很好的单一操作,可以在不使用寄存器的情况下否定布尔值并测试它是否为零。在这个 CPU 上,在寄存器压力的情况下,这可能会被优化为:

  1. 否定 thread_lock 并测试它是否为零。
  2. 如果 thread_lock 的副本为 false,则再次否定 thread_lock。

如果在第 1 步和第 2 步之间,另一个线程观察thread_locktrue即使它false正在进入此操作并且完成后也会出现false什么情况?


推荐阅读