[英]Is it undefined behavior to dereference a *mut T cast to *mut ManuallyDrop<T>?
[英]Cast &self to mut (to use predefined trait where it isn't mut)
我正在尝试实现分配器:
pub unsafe trait Allocator {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>;
...
请注意, &self 是不可变的。 我不确定哪种分配器能够在不更改分配器本身的情况下进行分配,但这是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<_, _>`
简而言之, 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
。
如果您实际使用的分配器是用 Rust 编写的并且本身是线程安全的(或部分/完全无锁),那么它的方法应该以&self
开头,并且您不需要互斥锁(因为互斥锁或其等价物将成为Mappoc
实现的一部分)。 如果Mappoc
的方法采用&mut self
,则意味着从多个线程调用它们是不安全的,Rust 强制您通过互斥体访问它们是一件好事。 这是完全按照设计工作的系统。
最后,一些分配器,如mimalloc
或jemalloc
,在 C 或 C++ 中实现,它们自己锁定。 但是他们的 Rust 前端也不需要&mut self
因为它们通过原始指针调用实际的分配器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.