在 C 管理的内存中正确存储 Rust Rc<T>
Correctly storing a Rust Rc<T> in C-managed memory
我正在包装一个 Rust 对象以供 Lua 使用。当 Rust 代码和 Lua 都没有对它的引用时,我需要销毁对象,所以(对我来说)显而易见的解决方案是使用 Rc<T>
,存储在 Lua-managed内存。
Lua API(我现在使用 rust-lua53)让你分配一块内存并附加方法和终结器,所以我想存储Rc<T>
进入那块内存。
我目前的尝试看起来像。一、创建对象:
/* Allocate a block of uninitialized memory to use */
let p = state.new_userdata(mem::size_of::<Rc<T>>() as size_t) as *mut Rc<T>;
/* Make a ref-counted pointer to a Rust object */
let rc = Rc::<T>::new(...);
/* Store the Rc */
unsafe { ptr::write(p, rc) };
在终结者中:
let p: *mut Rc<T> = ...; /* Get a pointer to the item to finalize */
unsafe { ptr::drop_in_place(p) }; /* Release the object */
现在这似乎可以工作了(通过向 drop
方法添加 println!() 进行了简短测试)。但它是否正确和安全(只要我确保它在完成后不被访问)?我对不安全的 Rust 没有足够的信心来确定 ptr::write 和 Rc<T>
.
是可以的
我也想知道,与其直接存储一个 Rc<T>
,不如存储一个 Option<Rc<T>>
;那么我会用 None
ptr::swap()
而不是 drop_in_place()
。这将使最终确定后的任何使用都变得容易。
Now this seems to work (as briefly tested by adding a println!() to the drop method). But is it correct and safe (as long as I make sure it's not accessed after finalisation)? I don't feel confident enough in unsafe Rust to be sure that it's ok to ptr::write an Rc<T>
.
是的,您可以 ptr::write
任何 Rust 类型到任何内存位置。这个"leaks" Rc<T>
对象,但是写了一个bit-equivalent 到目标位置。
使用它时,您需要保证没有人在 Rust 代码之外修改它,并且您仍然与创建它的线程处于同一线程中。如果你想能够跨线程移动,你需要使用Arc
.
Rust 的线程安全在这里无法保护你,因为你使用的是原始指针。
I'm also wondering about, rather than storing an Rc<T>
directly, storing an Option<Rc<T>>
; then instead of drop_in_place() I would ptr::swap() it with None. This would make it easy to handle any use after finalisation.
ptr::write
的吊坠是 ptr::read
。因此,如果您可以保证没有人尝试 ptr::read
或 drop_in_place()
对象,那么您可以调用 ptr::read
(returns 对象)并将该对象用作您将使用任何其他 Rc<T>
对象。你不需要关心掉落或其他任何事情,因为现在它又回到了 Rust 的控制之下。
您还应该使用 new_userdata_typed
而不是 new_userdata
,因为这样可以减轻您的内存处理负担。对于大多数用户数据需求,还有其他以后缀 _typed
结尾的便利包装函数。
您的代码将有效;当然,请注意 drop_in_place(p)
只会减少 Rc
的计数器,并且仅当且仅当它是最后一个引用时才删除包含的 T
,这是正确的操作。
我正在包装一个 Rust 对象以供 Lua 使用。当 Rust 代码和 Lua 都没有对它的引用时,我需要销毁对象,所以(对我来说)显而易见的解决方案是使用 Rc<T>
,存储在 Lua-managed内存。
Lua API(我现在使用 rust-lua53)让你分配一块内存并附加方法和终结器,所以我想存储Rc<T>
进入那块内存。
我目前的尝试看起来像。一、创建对象:
/* Allocate a block of uninitialized memory to use */
let p = state.new_userdata(mem::size_of::<Rc<T>>() as size_t) as *mut Rc<T>;
/* Make a ref-counted pointer to a Rust object */
let rc = Rc::<T>::new(...);
/* Store the Rc */
unsafe { ptr::write(p, rc) };
在终结者中:
let p: *mut Rc<T> = ...; /* Get a pointer to the item to finalize */
unsafe { ptr::drop_in_place(p) }; /* Release the object */
现在这似乎可以工作了(通过向 drop
方法添加 println!() 进行了简短测试)。但它是否正确和安全(只要我确保它在完成后不被访问)?我对不安全的 Rust 没有足够的信心来确定 ptr::write 和 Rc<T>
.
我也想知道,与其直接存储一个 Rc<T>
,不如存储一个 Option<Rc<T>>
;那么我会用 None
ptr::swap()
而不是 drop_in_place()
。这将使最终确定后的任何使用都变得容易。
Now this seems to work (as briefly tested by adding a println!() to the drop method). But is it correct and safe (as long as I make sure it's not accessed after finalisation)? I don't feel confident enough in unsafe Rust to be sure that it's ok to ptr::write an
Rc<T>
.
是的,您可以 ptr::write
任何 Rust 类型到任何内存位置。这个"leaks" Rc<T>
对象,但是写了一个bit-equivalent 到目标位置。
使用它时,您需要保证没有人在 Rust 代码之外修改它,并且您仍然与创建它的线程处于同一线程中。如果你想能够跨线程移动,你需要使用Arc
.
Rust 的线程安全在这里无法保护你,因为你使用的是原始指针。
I'm also wondering about, rather than storing an
Rc<T>
directly, storing anOption<Rc<T>>
; then instead of drop_in_place() I would ptr::swap() it with None. This would make it easy to handle any use after finalisation.
ptr::write
的吊坠是 ptr::read
。因此,如果您可以保证没有人尝试 ptr::read
或 drop_in_place()
对象,那么您可以调用 ptr::read
(returns 对象)并将该对象用作您将使用任何其他 Rc<T>
对象。你不需要关心掉落或其他任何事情,因为现在它又回到了 Rust 的控制之下。
您还应该使用 new_userdata_typed
而不是 new_userdata
,因为这样可以减轻您的内存处理负担。对于大多数用户数据需求,还有其他以后缀 _typed
结尾的便利包装函数。
您的代码将有效;当然,请注意 drop_in_place(p)
只会减少 Rc
的计数器,并且仅当且仅当它是最后一个引用时才删除包含的 T
,这是正确的操作。