编程系统/后端和嵌入式开发者

谈谈Rust中全局变量(static)的工作规则。如何在并发访问时确保安全,以及不同的初始化和同步方法有什么区别?

用 Hintsage AI 助手通过面试

回答

在Rust中,全局变量通过关键字static声明。这些变量在程序执行期间一直存在。默认情况下,对不可变static的访问是安全的,但对可变的则需要使用unsafe,因为编译器无法保证不存在线程竞争。

为了安全地访问可变全局变量,会使用特殊的包装类型:MutexRwLockAtomic*类型或外部的crate(如lazy_staticonce_cell)。初始化是"惰性"的,即在第一次访问时延迟创建对象。

示例:

static COUNTER: AtomicUsize = AtomicUsize::new(0); static ref CONFIG: Config = read_config(); // 通过lazy_static或once_cell

诱导性问题

是否可以在没有特殊类型的情况下声明可变全局变量,如果它只会在一个线程中使用?需要写 unsafe 吗?

回答: 编译器会要求在任何修改全局变量时使用unsafe,即使逻辑是单线程的。这是对所有static mut的普遍要求。只有当变量被封装在同步结构中(例如Mutex、原子等),编译器才会允许安全访问。

static mut VALUE: i32 = 0; unsafe { VALUE += 1; }

由于对主题细微差别的不理解而导致的实际错误示例


故事

在web服务中,在初始化全局缓存时使用了普通的static变量和字符串。多个线程同时写入,导致"内存炸弹"和应用程序崩溃,因为出现了线程竞争。


故事

在Rust命令行工具中,修改了没有同步的静态变量,因为"只通过main工作"。后来将代码屏蔽以适应多线程,忘记了全局可变状态,导致了非常难以发现的错误。


故事

在嵌入式程序中,错误地通过函数初始化了static CONFIG,但没有保证该函数将被调用一次,从而导致代码的某些部分访问未初始化的配置(空引用)。