Я хочу создать объект, который является «пустым», но может содержать сложные данные (здесь a
и b
), которые я могу обновить позже и установить флаг atomi c, чтобы пометить его как непустой, чтобы это может быть использовано в других темах. Псевдо пример:
use std::sync::atomic::{AtomicBool, Ordering};
use std::cell::Cell;
use std::sync::Arc;
use std::{thread, time};
struct MyObject {
is_empty: AtomicBool,
a: Cell<u64>,
b: Cell<u64>,
}
unsafe impl Sync for MyObject {}
fn main() {
let obj = Arc::new(MyObject {
is_empty: AtomicBool::new(true),
a: Cell::new(0),
b: Cell::new(0)
});
let thread_obj = obj.clone();
let t = thread::spawn(move || {
while thread_obj.is_empty.load(Ordering::SeqCst) {
thread::sleep(time::Duration::from_millis(10));
}
println!("a is: {}", thread_obj.a.get());
println!("b is: {}", thread_obj.b.get());
});
thread::sleep(time::Duration::from_millis(100));
obj.a.set(42);
obj.b.set(5);
obj.is_empty.store(false, Ordering::SeqCst);
t.join().unwrap();
}
Посмотрите на Rust Playground
Это кажется работать, но это не много значит. Меня больше всего беспокоит, будут ли записи в a
и b
определенно видны другим потокам, которые читают is_empty
как ложное. Если я гарантирую:
- все записи в
a
и b
происходят до установки флага - , ни один поток не читает
a
и b
до установки флага
это нормально?
Я мог бы вместо этого использовать AtomicPtr
, создать объект полностью и поменять местами указатель, но мне любопытно, могу ли я избежать дополнительной косвенности .