from the doc:
BytesMut represents a unique view into a potentially shared memory region. Given the uniqueness guarantee, owners of BytesMut handles are able to mutate the memory.
BytesMut can be thought of as containing a buf: Arc<Vec>, an offset into buf, a slice length, and a guarantee that no other BytesMut for the same buf overlaps with its slice. That guarantee means that a write lock is not required.
why multiple owners of BytesMut can mutate the memory concurrently?
why a write lock is not required?
how is it implemented?
why multiple owners of BytesMut can mutate the memory concurrently?
why a write lock is not required?
From the docs: and a guarantee that no other BytesMut for the same buf overlaps with its slice.
There is no overlap, so it is safe to mutate it since no one else can mutate that region. Also no lock need for the same reason, no synchronization is needed since there is no overlap.
how is it implemented?
You can take a look at the source code
Related
If I have an Option<T> and I construct T, and then assign this, will the operation be atomic, as in will other threads get either None or Some(T) but definitely not part of Some(T)?
No. Option is not designed with thread synchronization in mind.
However, you cannot observe interleaved reads because Rust's memory safety prevents you from modifying a value at all while its referenced in another thread. You would need a synchronization primitive like Mutex or RwLock to do that.
There is the atomic-option crate. Or perhaps just use an AtomicPtr.
Is there any option to use shared memory for Vec<f64> in Rust?
Processes in my program swap two or more values in a Vec<f64> and I need the memory to be shared between processes.
There is no way to safely create a Vec backed by shared memory. There are two reasons this is true:
A Vec owns its memory and will reallocate it when grown or free it when dropped. Unsafely creating a Vec pointing to mmapped memory will corrupt the heap when the Vec reallocates or goes out of scope.
A Vec has exclusive access to its memory, like a &mut reference. The compiler is free to omit and reorder reads and writes based on the assumption that nothing else is using the memory. If this assumption is broken, the behavior is undefined. To relax this assumption, your data type needs to be something based on UnsafeCell.
Vec is the wrong pointer for this job. Try &[UnsafeCell<f64>], or maybe &[AtomicU64] (with conversions using from_bits and to_bits), since there isn't an AtomicF64 in the standard library.
From what I've learned, I should always choose Arc<T> for shared read access across threads and Arc<Mutex<T>> for shared write access across threads. Are there cases where I don't want to use Arc<T>/Arc<Mutex<T>> and instead do something completely different? E.g. do something like this:
unsafe impl Sync for MyStruct {}
unsafe impl Send for MyStruct {}
let shared_data_for_writing = Arc::from(MyStruct::new());
Sharing across threads
Besides Arc<T>, we can share objects across threads using scoped threads, e.g. by using crossbeam::scope and Scope::spawn. Scoped threads allow us to send borrowed pointers (&'a T) to threads spawned in a scope. The scope guarantees that the thread will terminate before the referent is dropped. Borrowed pointers have no runtime overhead compared to Arc<T> (Arc<T> takes a bit more memory and needs to maintain a reference counter using atomic instructions).
Mutating across threads
Mutex<T> is the most basic general-purpose wrapper for ensuring at most one thread may mutate a value at any given time. Mutex<T> has one drawback: if there are many threads that only want to read the value in the mutex, they can't do so concurrently, even though it would be safe. RwLock<T> solves this by allowing multiple concurrent readers (while still ensuring a writer has exclusive access).
Atomic types such as AtomicUsize also allow mutation across threads, but only for small values (8, 16, 32 or 64 bits – some processors support atomic operations on 128-bit values, but that's not exposed in the standard library yet; see atomic::Atomic for that). For example, instead of Arc<Mutex<usize>>, you could use Arc<AtomicUsize>. Atomic types do not require locking, but they are manipulated through atomic machine instructions. The set of atomic instructions is a bit different from the set of non-atomic instructions, so switching from a non-atomic type to an atomic type might not always be a "drop-in replacement".
I have a tree and I want each node of the tree to have a pointer to its parent.
struct DataDeclaration {
parent: Option<Arc<DataDeclaration>>,
children: Option<Vec<Weak<DataDeclaration>>>,
properties: HashMap<Identifier, DataDeclarationProperty>,
}
This creates a cycle, so I use Weak to make sure the memory doesn’t live indefinitely. This tree will be immutable for the entire length of my application except, of course, when the tree is constructed.
In order to create this tree, do I need to use a Mutex or RwLock from the standard library or parking_lot? Will there be a negative performance impact if I only use the lock for reads?
do I need to use a Mutex or RwLock
Yes.
There's no practical way to have the type be temporarily mutable while you construct it and then "jettisoning" the ability to be mutated for some period of time (until destruction when it needs to become mutable again)
Will there be a negative performance impact
Yes.
Will the impact be meaningful or important? That depends on a whole host of factors that are not answerable outside of the scope of your entire program and a specific set of usages.
The impact will probably be higher if you use a Mutex instead of a RwLock as a Mutex only allows one thread access at a time. A RwLock will allow multiple concurrent threads.
See also:
Is there an alternative or way to have Rc<RefCell<X>> that restricts mutability of X?
Everything here is also true for single-threaded contexts, replacing Arc with Rc and RwLock with RefCell.
Basically I have a heap-allocated struct Box<State>. I have multiple Value structs that need to have an immutable reference to this heap-allocated struct.
What kind of attribute can I use inside of Value for this reference? Using Rc<Box<State>> does not work because I need Value to implement Copy and State does not implement Copy. When it needs to copy itself, I just want to copy the pointer to that heap-allocated State.
What you're asking for is basically impossible. If you have many pointers to the heap allocation floating around, you need to somehow keep track of these pointers to be able to deallocate once all these pointers are destroyed. However, that requires doing something whenever one of the pointer is duplicated, and/or doing something when the pointers are destroyed.
Well, that's not quite true, there are two ways around this:
Don't deallocate, i.e., leak memory
Have a garbage collector periodically going through all memory that might contain pointers to the allocation.
But the first is impractical in most contexts (and quite dirty even when you can afford it), and the second has other costs and far-reaching consequences and is not really well supported in current Rust anyway.
The only sane thing is to drop the Copy requirement. Perhaps you're confusing Copy with Clone? The primary difference between the two is that you have to call clone() explicitly while Copy works implicitly. Rc<anything> is Clone and cloning the reference counted pointer will only increment the refcount, not clone the thing behind the pointer. (And in this case you almost certainly can and should get rid of the Box, since Rc<T> already allocates the T on the heap, so the Box is just a pointless additional indirection.)