matklad / once_cell

Rust library for single assignment cells and lazy statics without macros

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Q: sync::OnceCell (compare with unsync::OnceCell) only protect set() & get() operations?

mw66 opened this issue · comments

commented

Hi,

Sorry for a rust newbie question.

I want to confirm that sync::OnceCell (compare with unsync::OnceCell) only protect the cell's set() & get() operations?

Suppose I'm using OnceCell<AThreadSafeContainer>, and I init the cell only once in the main thread at program start (and never change what the cell holds anymore):

e.g.

https://docs.rs/dashmap/5.3.4/dashmap/struct.DashMap.html#method.insert

use once_cell::unsync::OnceCell;  // from unsync !


type HashMapT = DashMap<u64, u64>;   // DashMap is a thread-safe container

// have to use `mut` here
static mut HASHMAP: OnceCell<HashMapT> = OnceCell::with_value(HashMapT::new());

then I can change what the container holds:

// in producer thread:
  HASHMAP.get_mut().unwrap().insert(key, val).unwrap()

and

// in consumer thread:
  *(HASHMAP.get_mut().unwrap().get(&key).unwrap())

so, this usage is still thread safe, right? i.e. the single global instance cell (HASHMAP)'s get() access no need to protected by Mutex, as long as the container itself (the DashMap) is a thread-safe container.

Thanks.

No, the above is not safe -- to the first approximation, static mut can't be used in a safe way at all. The good news is that you don't need static mut here:

type HashMapT = DashMap<u64, u64>;
static HASHMAP: once_cell::sync::Lazy<HashMapT> = once_cell::sync::Lazy::new(HashMapT::new);

// in producer thread:
HASHMAP.insert(key, val).unwrap()

// in consumer thread:
HASHMAP.get(&key).unwrap())
commented

Thanks for the quick reply. One more question:

In this case, will each hashmap's access incur two syncs? first sync on the cell HASHMAP, and 2nd sync on the container itself (insert, or get)?

If this is true, I want to avoid the the 1st sync on the cell, since the cell's contents never change (only the container's content will change). Is this doable?

The first "sync" is just a relaxed load, its cost should be negligible in comparison to the hash map lookup to follow.

I don't think completely eliminating any synchronization is possible to express in safe Rust.

commented

ok, thanks!