From 5bf04a4afcc866f52e86d70dc5688e7a1799c57b Mon Sep 17 00:00:00 2001 From: Matthias Geier Date: Mon, 6 Dec 2021 20:54:38 +0100 Subject: [PATCH] Use "Relaxed" for reading tail in producer and head in consumer --- src/chunks.rs | 15 ++++++++++----- src/lib.rs | 12 ++++++++---- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/chunks.rs b/src/chunks.rs index ee99352..e6d9d3b 100644 --- a/src/chunks.rs +++ b/src/chunks.rs @@ -237,7 +237,8 @@ impl Producer { /// For a safe alternative that provides mutable slices of [`Default`]-initialized slots, /// see [`Producer::write_chunk()`]. pub fn write_chunk_uninit(&mut self, n: usize) -> Result, ChunkError> { - let tail = self.buffer.tail.load(Ordering::Acquire); + // "tail" is only ever written by the producer thread, "Relaxed" is enough + let tail = self.buffer.tail.load(Ordering::Relaxed); // Check if the queue has *possibly* not enough slots. if self.buffer.capacity - self.buffer.distance(self.cached_head.get(), tail) < n { @@ -286,7 +287,8 @@ impl Consumer { /// /// See the documentation of the [`chunks`](crate::chunks#examples) module. pub fn read_chunk(&mut self, n: usize) -> Result, ChunkError> { - let head = self.buffer.head.load(Ordering::Acquire); + // "head" is only ever written by the consumer thread, "Relaxed" is enough + let head = self.buffer.head.load(Ordering::Relaxed); // Check if the queue has *possibly* not enough slots. if self.buffer.distance(head, self.cached_tail.get()) < n { @@ -481,7 +483,8 @@ impl WriteChunkUninit<'_, T> { unsafe fn commit_unchecked(self, n: usize) -> usize { let p = self.producer; - let tail = p.buffer.tail.load(Ordering::Acquire); + // "tail" is only ever written by the producer thread, "Relaxed" is enough + let tail = p.buffer.tail.load(Ordering::Relaxed); let tail = p.buffer.increment(tail, n); p.buffer.tail.store(tail, Ordering::Release); n @@ -681,7 +684,8 @@ impl ReadChunk<'_, T> { self.second_ptr.add(i).drop_in_place(); } let c = self.consumer; - let head = c.buffer.head.load(Ordering::Acquire); + // "head" is only ever written by the consumer thread, "Relaxed" is enough + let head = c.buffer.head.load(Ordering::Relaxed); let head = c.buffer.increment(head, n); c.buffer.head.store(head, Ordering::Release); n @@ -735,7 +739,8 @@ impl<'a, T> Drop for ReadChunkIntoIter<'a, T> { /// Non-iterated items remain in the ring buffer and are *not* dropped. fn drop(&mut self) { let c = &self.chunk.consumer; - let head = c.buffer.head.load(Ordering::Acquire); + // "head" is only ever written by the consumer thread, "Relaxed" is enough + let head = c.buffer.head.load(Ordering::Relaxed); let head = c.buffer.increment(head, self.iterated); c.buffer.head.store(head, Ordering::Release); } diff --git a/src/lib.rs b/src/lib.rs index 9f1e55e..441274c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -338,7 +338,8 @@ impl Producer { pub fn slots(&self) -> usize { let head = self.buffer.head.load(Ordering::Acquire); self.cached_head.set(head); - let tail = self.buffer.tail.load(Ordering::Acquire); + // "tail" is only ever written by the producer thread, "Relaxed" is enough + let tail = self.buffer.tail.load(Ordering::Relaxed); self.buffer.capacity - self.buffer.distance(head, tail) } @@ -434,7 +435,8 @@ impl Producer { /// This is a strict subset of the functionality implemented in `write_chunk_uninit()`. /// For performance, this special case is immplemented separately. fn next_tail(&self) -> Option { - let tail = self.buffer.tail.load(Ordering::Acquire); + // "tail" is only ever written by the producer thread, "Relaxed" is enough + let tail = self.buffer.tail.load(Ordering::Relaxed); // Check if the queue is *possibly* full. if self.buffer.distance(self.cached_head.get(), tail) == self.buffer.capacity { @@ -570,9 +572,10 @@ impl Consumer { /// assert_eq!(c.slots(), 0); /// ``` pub fn slots(&self) -> usize { - let head = self.buffer.head.load(Ordering::Acquire); let tail = self.buffer.tail.load(Ordering::Acquire); self.cached_tail.set(tail); + // "head" is only ever written by the consumer thread, "Relaxed" is enough + let head = self.buffer.head.load(Ordering::Relaxed); self.buffer.distance(head, tail) } @@ -667,7 +670,8 @@ impl Consumer { /// This is a strict subset of the functionality implemented in `read_chunk()`. /// For performance, this special case is immplemented separately. fn next_head(&self) -> Option { - let head = self.buffer.head.load(Ordering::Acquire); + // "head" is only ever written by the consumer thread, "Relaxed" is enough + let head = self.buffer.head.load(Ordering::Relaxed); // Check if the queue is *possibly* empty. if head == self.cached_tail.get() {