use std::mem::MaybeUninit;
use sync::*; // pub(crate) use std::sync::atomic::{AtomicPtr, Ordering, fence};
mod sync;
struct Stack<T> {
head: AtomicPtr<Node<T>>,
}
impl<T> Drop for Stack<T> {
fn drop(&mut self) {
// todo!()
}
}
unsafe impl<T: Send> Send for Stack<T> {}
unsafe impl<T> Sync for Stack<T> {}
struct Node<T> {
data: MaybeUninit<T>,
next: *mut Node<T>,
}
impl<T> Stack<T> {
fn new() -> Self {
Self {
head: AtomicPtr::new(std::ptr::null_mut()),
}
}
fn push(&self, data: T) {
let node = Box::into_raw(Box::new(Node {
data: MaybeUninit::new(data),
next: std::ptr::null_mut(),
}));
let mut head = self.head.load(Ordering::Relaxed);
loop {
unsafe { &mut *node }.next = head;
match self
.head
.compare_exchange_weak(head, node, Ordering::Release, Ordering::Relaxed)
{
Ok(_) => break,
Err(actual) => {
head = actual;
}
}
}
}
fn pop(&self) -> Option<T> {
let mut head = self.head.load(Ordering::Relaxed);
// this fence prevents the above load from loading a detached head...
// because a detached head is deallocated and we might dereference it to reach `next`.
fence(Ordering::SeqCst); // a SC fence here (to synchronize with the below fence)
loop {
if head.is_null() {
return None;
}
let next = unsafe { &*head }.next;
match self
.head
.compare_exchange_weak(head, next, Ordering::Relaxed, Ordering::Relaxed)
{
Ok(head) => {
fence(Ordering::SeqCst); // a SC fence here
let data = unsafe { (&mut *head).data.assume_init_read() };
drop(unsafe { Box::from_raw(head) });
return Some(data);
}
Err(actual) => {
head = actual;
}
}
}
}
}
some things that could be wrong and are confusing:
mixing memory orderings with SeqCst, should I avoid this? Is the behavior unpredictable?
Does SeqCst Ordering act correctly on the load? (an Acquire fence is placed below the load, so I just placed the SeqCst fence below as well.)
Can the job be done with just a single SeqCst fence?
How to test this? I tried testing this very basic implementation using loom, but loom doesn't seem to be complaining even when I comment out the fences
I know that I could have used some very nice crates for memory reclamation here, but I was just trying things. Same thing goes for using fences and not using Ordering::SeqCst directly on the atomic operation
13 posts - 4 participants
Read full topic
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | Type erasure and dyn lifetime in a NonNull/Box struct field | 0 | 8.55 | 04-10-2026 |
| 2 | Are there wait-free priority queue crates? | 0 | 16.09 | 05-10-2026 |
| 3 | Arena's and alignment | 0 | 7.3 | 04-10-2026 |
| 4 | Architecture review of a Hyper/Tower-based web framework (Toxi) | 0 | 15.46 | 06-10-2026 |
| 5 | Strategies for dyn trait objects with optional behavior? | 0 | 7.12 | 06-10-2026 |
| 6 | Why no Dependent Matrix Type? | 0 | 5.16 | 08-10-2026 |
| 7 | What's everyone working on this week (41/2026)? | 0 | 20.34 | 06-10-2026 |
| 8 | Calling static C++ method from Rust | 0 | 9.94 | 04-10-2026 |
| 9 | Optimization of inlined functions returning Result? | 0 | 7.36 | 06-10-2026 |
| 10 | Why is f32/f64::sqrt not const? | 0 | 22.72 | 06-10-2026 |