`UnsafeCell` and slices, and decrete `RwLock`s

โš“ Rust    ๐Ÿ“… 2026-07-15    ๐Ÿ‘ค surdeus    ๐Ÿ‘๏ธ 2      

surdeus

Background

I am trying to implement a flat list which contains sublists of the same size where each sublist is guarded by its own RwLock.

So, something like this:

use std::cell::UnsafeCell;
use crossbeam::utils::CachePadded;
use parking_lot::RwLock;

struct Layers {
    data: Box<[UnsafeCell<u32>]>, // I may have say N "virtual array" of size 16.
    rwlocks: Box<[CachePadded<RwLock<()>>]>, // Then, I will have an RwLock for each "virtual array", so a total of N here.
}

First Question

Which type should be used for data?

  • Box<UnsafeCell<[u32]>>: It's quite unintuitive to create a value of this type, one has to go through Vec::into_boxed_slice, Box::into_raw, pointer casting, Box::from_raw, etc. But I think this has the "most correct" provenance for the pointers obtained from UnsafeCell in the sense that they have write permission over the whole region of the slice.
  • Box<[UnsafeCell<u32>]>: For my use case, I will need to mutate other elements through a pointer to some element. In my understanding, the pointer may have the correct spatial permission as it inherited that from the slice but may not have the correct mutation permission (due to the requirement to use UnsafeCell::get and UnsafeCell::raw_get). In Does UnsafeCell::raw_get preserve pointer provenance? ยท Issue #474 ยท rust-lang/unsafe-code-guidelines ยท GitHub, RalfJung mentioned that:
    1. ... However we reserve the right to have something more strict in the future where if you do not go through raw_get, you are not allowed to perform mutation of the cell's contents ...
    2. UnsafeCell::raw_get does not do any "narrowing" of provenance to the type -- the entire memory range of the original provenance is preserved ...
  • UnsafeCell<Box<[u32]>: This feels even more wrong, to me the UnsafeCell is not enabling interior mutability to the memory region but the Box itself instead.

Second Question

Is it sound/safe/etc. to use separated RwLocks that doesn't wrap the values (i.e., RwLock<()>)?

For one, although I believe RwLock does provide the required semantics for MT-safe access, UnsafeCell only mentioned atomics for synchronizing conflicting access: ... conflicting non-synchronized accesses must be done via the APIs in core::sync::atomic..

I'm not even sure if my reasoning is correct. Please correct me if there is any inaccurate description of the semantics. Help appreciated!

FYR: Read/Write guard for sublists (click for more details)

1 post - 1 participant

Read full topic

๐Ÿท๏ธ Rust_feed