我想了解如果我的程序在单核计算机上运行,为什么在 Rust 中使用不安全代码来访问 Rust 中的共享资源/变量是不安全的。 ChatGPT 和 ClaudeAI 都表示这段代码即使在单核计算机上运行也是不安全的:
use std::collections::HashMap;
static mut UNSAFE_MAP: Option<HashMap<u32, u32>> = None;
#[tokio::main(flavor = "current_thread")]
async fn main() {
// Initialize map
unsafe { UNSAFE_MAP = Some(HashMap::new()); }
let task1 = tokio::spawn(async {
for i in 0..10_000_000u32 {
unsafe {
if let Some(map) = &mut UNSAFE_MAP {
map.insert(i, i);
}
}
}
});
let task2 = tokio::spawn(async {
for i in 0..10_000_000u32 {
unsafe {
if let Some(map) = &mut UNSAFE_MAP {
map.insert(i + 10_000_000, i);
}
}
}
});
// Wait for both tasks
let _ = tokio::join!(task1, task2);
// Check final state
unsafe {
if let Some(map) = &UNSAFE_MAP {
println!("Final map size: {}", map.len());
// Should be 20 million if everything worked
}
}
}
我了解操作系统可以在任何给定时间停止我的程序。但是,一旦恢复,它应该继续按原定的顺序运行?我还了解到,如果两个 tokio 线程都写入同一个文件或在没有同步/锁的情况下执行任何与操作系统相关的操作,则可能会出现问题。我有一台托管在 AWS 上的单核计算机,我想使用不安全的代码来避免锁定。我实际上正在构建一个 RTP 服务器,所以没有锁会很好。我已经运行这个代码一小时了,但没能让它失败。
这段代码只是我实际程序中的一个示例,我计划有一个指向保存所有共享资源的结构的指针。我大部分时间都会阅读,偶尔也会写入哈希图。由于我正在构建一个 RTP 服务器,即使我使用 RwLock,如果我计划拥有 100 个并发调用,也需要很长时间。
我了解操作系统可以在任何给定时间停止我的程序。
它还可以随时更改正在运行的线程。假设您的 Task1 线程正在向映射中插入值,并且刚刚选择要使用的存储桶并验证它未满。然后操作系统决定切换到 Task2 线程,该线程将一个值插入到同一个存储桶中。然后第一个威胁再次开始运行,并覆盖第二个线程插入的值(因为它认为存储桶仍然可用)。
线程抢占比进程抢占更常见不安全。