multithreading - 为什么布尔值需要是原子的?
问题描述
在 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。
解决方案
AtomicBool 究竟能保护我们免受什么影响?为什么我们不能使用来自不同线程的常规布尔值(除了编译器不允许我们这样做)?
任何可能出错的事情,不管你能不能想到。我讨厌用我能想到的东西来跟进这件事,因为这无关紧要。规则说它不能保证有效,应该结束它。认为你必须想出一种可能失败或不能失败的方法是错误的。
但这是一种方法:
// Release the lock
thread_lock = false
假设这个特定的 CPU 没有特别好的方法可以在不使用寄存器的情况下将布尔值设置为 false,但确实有一个很好的单一操作,可以在不使用寄存器的情况下否定布尔值并测试它是否为零。在这个 CPU 上,在寄存器压力的情况下,这可能会被优化为:
- 否定 thread_lock 并测试它是否为零。
- 如果 thread_lock 的副本为 false,则再次否定 thread_lock。
如果在第 1 步和第 2 步之间,另一个线程观察thread_lock
到true
即使它false
正在进入此操作并且完成后也会出现false
什么情况?
推荐阅读
- ruby-on-rails - 后控制器需要后
- python - 使用 pynput 在随机位置自动单击鼠标(用于网络浏览器游戏)
- python - 在 powershell 中运行 python 文件
- java - 在 JSR 303 bean 验证单元测试中,如何检查违反了哪些约束
- clojure - Clojure 调用一系列函数并存储它们的返回值
- django - 如何通过 id 在 Django 中加入两个模型?
- vue.js - 更改网址后立即停止观看
- ios - 如何在 SwiftUI 中使用图像 CDN?
- python - 如何在命令行上使用“python -c”缩进
- xcode - 由于 pod 链接错误,Flutter 归档构建失败