如何在Rust中获得一个简单的可变线程本地结构



我正在用垃圾收集器构建一个解释器。我想要一个线程本地托儿所区域,以及一个共享的旧区域。我在布置托儿所时遇到了麻烦。我有:

const NurserySize : usize = 25000;
#[thread_local]
static mut NurseryMemory : [usize;NurserySize] = [0;NurserySize];
thread_local! {
static Nursery: AllocableRegion = AllocableRegion::makeLocal(unsafe{&mut NurseryMemory});
}
#[cfg(test)]
mod testMemory {
use super::*;
#[test]
fn test1() {
Nursery.with(|n| n.allocObject(10));
}
}

第一个问题是为什么我需要不安全的——NurseryMemory是线程本地的,所以访问不可能是不安全的?

第二个问题是我该如何使用它?代码在操场上,但它没有编译,我试图修复它似乎让它变得更糟。

1。为什么获取对可变ThreadLocal的引用是不安全的

对于一个普通的可变静态,你需要不安全的原因是一样的,您将能够在安全代码中创建别名mut指针。以下错误地创建了对可变线程local的两个可变引用。

#![feature(thread_local)]
#[thread_local]
static mut SomeValue: Result<&str, usize> = Ok("hello world");
pub fn main() {
let first = unsafe {&mut SomeValue};
let second = unsafe {&mut SomeValue};
if let Ok(string) = first {
*second = Err(0); // should invalidate the string reference, but it doesn't 
println!("{}", string) // as first and second are considered to be disjunct
} 

}

first甚至不需要是一个可变的引用,这就成了一个问题。

2.如何修复代码

您可以在AllocatableRegion周围使用RefCell来动态强制内部值的借用。

const NurserySize : usize = 25000;
#[thread_local]
static mut NurseryMemory : [usize;NurserySize] = [0;NurserySize];
thread_local! {
static Nursery: RefCell<AllocableRegion> = RefCell::new(AllocableRegion::makeLocal(unsafe{&mut NurseryMemory}));
}
#[cfg(test)]
mod testMemory {
use super::*;
#[test]
fn test1() {
Nursery.with(|n| n.borrow_mut().allocObject(10));
}
}

您不需要unsafe来在rust中创建可变线程本地结构。然而,托儿所确实需要成为RefCell。这就足够了:

use std::cell::RefCell;
const NURSERY_SIZE: usize = 300;
thread_local! {
static NURSERY: RefCell<[usize; NURSERY_SIZE]> = RefCell::new([0; NURSERY_SIZE]);
}
#[cfg(test)]
mod test_memory {
use super::*;
#[test]
fn test1() {
NURSERY.with(|n| n.borrow_mut()[10] = 20);
}
}

Rust Playground链接

最新更新