我正在尝试实现分配器:
pub unsafe trait Allocator {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>;
...
请注意,&自我是不可变的。我不确定什么样的分配器能够在不改变分配器本身的情况下进行分配,但这正是vec
准备与之对话的,所以我想我必须忍受它
- 他们应该制作&自我沉默还是我错过了什么
- 我如何残酷地铸造这个&自我变成哑巴
我试着在impl:中粘贴mut
unsafe impl Allocator for Mappoc {
fn allocate(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
...
但上面写着:
|| error[E0053]: method `allocate` has an incompatible type for trait
src/lib.rs|110| 17
|| |
|| 110 | fn allocate(&mut self, layout: Layout)
|| | ^^^^^^^^^
|| | |
|| | types differ in mutability
|| | help: change the self-receiver type to match the trait: `self: &Mappoc`
|| |
|| = note: expected fn pointer `fn(&Mappoc, std::alloc::Layout) -> Result<_, _>`
|| found fn pointer `fn(&mut Mappoc, std::alloc::Layout) -> Result<_, _>`
正如注释中所指出的,将&self
强制转换为&mut
是未定义的行为,即使在不安全的代码中也是不允许的(尽管编译器无法阻止您在不安全块中执行此操作(。幸运的是,它不需要。
allocate()
采用&self
,以允许从多个线程使用分配器。(请记住,&mut
引用是独占的,一次只能存在一个。(从不可变引用中获得可变引用的最简单的线程安全方法是将实际分配器封装在互斥对象中:
struct MappocAllocator {
inner: Mutex<Mappoc>, // your actual allocator
}
impl Allocator for MappocAllocator {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
let alloc = self.inner.lock().unwrap();
// now you have access to `&mut Mappoc` for the duration of the lock
...
}
}
我不确定在不更改分配器本身的情况下,哪种分配器能够分配
这是对&T
含义的误解。共享引用并不一定意味着它下面的数据不会改变,它意味着多个参与者同时使用它是安全的。例如,无锁的可变API总是采用&self
。
如果Mappoc
分配器是用Rust编写的,并且本身是线程安全的(或部分/完全无锁(,那么它的方法应该从&self
开始,并且您不需要互斥(因为互斥或其等价物将是Mappoc
实现的一部分(。如果Mappoc
的方法采用&mut self
,这意味着从多个线程调用它们是不安全的,并且Rust强制您通过互斥锁访问它们是一件好事。这是一个完全按照设计工作的系统。
最后,一些分配器,如mimalloc
或jemalloc
,是在C或C++中实现的,它们自己进行锁定。但是它们的Rust前端也不需要&mut self
,因为它们通过原始指针调用实际的分配器。