114
114
use crate :: sync:: notify:: Notify ;
115
115
116
116
use crate :: loom:: sync:: atomic:: AtomicUsize ;
117
- use crate :: loom:: sync:: atomic:: Ordering :: Relaxed ;
117
+ use crate :: loom:: sync:: atomic:: Ordering ;
118
118
use crate :: loom:: sync:: { Arc , RwLock , RwLockReadGuard } ;
119
119
use std:: fmt;
120
120
use std:: mem;
@@ -247,7 +247,8 @@ struct Shared<T> {
247
247
248
248
impl < T : fmt:: Debug > fmt:: Debug for Shared < T > {
249
249
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
250
- let state = self . state . load ( ) ;
250
+ // Using `Relaxed` ordering is sufficient for this purpose.
251
+ let state = self . state . load ( Ordering :: Relaxed ) ;
251
252
f. debug_struct ( "Shared" )
252
253
. field ( "value" , & self . value )
253
254
. field ( "version" , & state. version ( ) )
@@ -341,7 +342,7 @@ mod big_notify {
341
342
/// This function implements the case where randomness is not available.
342
343
#[ cfg( not( all( not( loom) , feature = "sync" , any( feature = "rt" , feature = "macros" ) ) ) ) ]
343
344
pub ( super ) fn notified ( & self ) -> Notified < ' _ > {
344
- let i = self . next . fetch_add ( 1 , Relaxed ) % 8 ;
345
+ let i = self . next . fetch_add ( 1 , Ordering :: Relaxed ) % 8 ;
345
346
self . inner [ i] . notified ( )
346
347
}
347
348
@@ -357,7 +358,7 @@ mod big_notify {
357
358
use self :: state:: { AtomicState , Version } ;
358
359
mod state {
359
360
use crate :: loom:: sync:: atomic:: AtomicUsize ;
360
- use crate :: loom:: sync:: atomic:: Ordering :: SeqCst ;
361
+ use crate :: loom:: sync:: atomic:: Ordering ;
361
362
362
363
const CLOSED_BIT : usize = 1 ;
363
364
@@ -377,6 +378,11 @@ mod state {
377
378
pub ( super ) struct StateSnapshot ( usize ) ;
378
379
379
380
/// The state stored in an atomic integer.
381
+ ///
382
+ /// The `Sender` uses `Release` ordering for storing a new state
383
+ /// and the `Receiver`s use `Acquire` ordering for loading the
384
+ /// current state. This ensures that written values are seen by
385
+ /// the `Receiver`s for a proper handover.
380
386
#[ derive( Debug ) ]
381
387
pub ( super ) struct AtomicState ( AtomicUsize ) ;
382
388
@@ -412,18 +418,32 @@ mod state {
412
418
}
413
419
414
420
/// Load the current value of the state.
415
- pub ( super ) fn load ( & self ) -> StateSnapshot {
416
- StateSnapshot ( self . 0 . load ( SeqCst ) )
421
+ pub ( super ) fn load ( & self , ordering : Ordering ) -> StateSnapshot {
422
+ StateSnapshot ( self . 0 . load ( ordering) )
423
+ }
424
+
425
+ /// Load the current value of the state.
426
+ ///
427
+ /// The receiver side (read-only) uses `Acquire` ordering for a proper handover
428
+ /// with the sender side (single writer).
429
+ pub ( super ) fn load_receiver ( & self ) -> StateSnapshot {
430
+ StateSnapshot ( self . 0 . load ( Ordering :: Acquire ) )
417
431
}
418
432
419
433
/// Increment the version counter.
420
434
pub ( super ) fn increment_version ( & self ) {
421
- self . 0 . fetch_add ( STEP_SIZE , SeqCst ) ;
435
+ // Use `Release` ordering to ensure that storing the version
436
+ // state is seen by the receiver side that uses `Acquire` for
437
+ // loading the state.
438
+ self . 0 . fetch_add ( STEP_SIZE , Ordering :: Release ) ;
422
439
}
423
440
424
441
/// Set the closed bit in the state.
425
442
pub ( super ) fn set_closed ( & self ) {
426
- self . 0 . fetch_or ( CLOSED_BIT , SeqCst ) ;
443
+ // Use `Release` ordering to ensure that storing the version
444
+ // state is seen by the receiver side that uses `Acquire` for
445
+ // loading the state.
446
+ self . 0 . fetch_or ( CLOSED_BIT , Ordering :: Release ) ;
427
447
}
428
448
}
429
449
}
@@ -489,7 +509,7 @@ impl<T> Receiver<T> {
489
509
fn from_shared ( version : Version , shared : Arc < Shared < T > > ) -> Self {
490
510
// No synchronization necessary as this is only used as a counter and
491
511
// not memory access.
492
- shared. ref_count_rx . fetch_add ( 1 , Relaxed ) ;
512
+ shared. ref_count_rx . fetch_add ( 1 , Ordering :: Relaxed ) ;
493
513
494
514
Self { shared, version }
495
515
}
@@ -543,7 +563,7 @@ impl<T> Receiver<T> {
543
563
544
564
// After obtaining a read-lock no concurrent writes could occur
545
565
// and the loaded version matches that of the borrowed reference.
546
- let new_version = self . shared . state . load ( ) . version ( ) ;
566
+ let new_version = self . shared . state . load_receiver ( ) . version ( ) ;
547
567
let has_changed = self . version != new_version;
548
568
549
569
Ref { inner, has_changed }
@@ -590,7 +610,7 @@ impl<T> Receiver<T> {
590
610
591
611
// After obtaining a read-lock no concurrent writes could occur
592
612
// and the loaded version matches that of the borrowed reference.
593
- let new_version = self . shared . state . load ( ) . version ( ) ;
613
+ let new_version = self . shared . state . load_receiver ( ) . version ( ) ;
594
614
let has_changed = self . version != new_version;
595
615
596
616
// Mark the shared value as seen by updating the version
@@ -631,7 +651,7 @@ impl<T> Receiver<T> {
631
651
/// ```
632
652
pub fn has_changed ( & self ) -> Result < bool , error:: RecvError > {
633
653
// Load the version from the state
634
- let state = self . shared . state . load ( ) ;
654
+ let state = self . shared . state . load_receiver ( ) ;
635
655
if state. is_closed ( ) {
636
656
// The sender has dropped.
637
657
return Err ( error:: RecvError ( ( ) ) ) ;
@@ -768,7 +788,7 @@ impl<T> Receiver<T> {
768
788
{
769
789
let inner = self . shared . value . read ( ) . unwrap ( ) ;
770
790
771
- let new_version = self . shared . state . load ( ) . version ( ) ;
791
+ let new_version = self . shared . state . load_receiver ( ) . version ( ) ;
772
792
let has_changed = self . version != new_version;
773
793
self . version = new_version;
774
794
@@ -814,7 +834,7 @@ fn maybe_changed<T>(
814
834
version : & mut Version ,
815
835
) -> Option < Result < ( ) , error:: RecvError > > {
816
836
// Load the version from the state
817
- let state = shared. state . load ( ) ;
837
+ let state = shared. state . load_receiver ( ) ;
818
838
let new_version = state. version ( ) ;
819
839
820
840
if * version != new_version {
@@ -865,7 +885,7 @@ impl<T> Drop for Receiver<T> {
865
885
fn drop ( & mut self ) {
866
886
// No synchronization necessary as this is only used as a counter and
867
887
// not memory access.
868
- if 1 == self . shared . ref_count_rx . fetch_sub ( 1 , Relaxed ) {
888
+ if 1 == self . shared . ref_count_rx . fetch_sub ( 1 , Ordering :: Relaxed ) {
869
889
// This is the last `Receiver` handle, tasks waiting on `Sender::closed()`
870
890
self . shared . notify_tx . notify_waiters ( ) ;
871
891
}
@@ -1228,7 +1248,7 @@ impl<T> Sender<T> {
1228
1248
/// ```
1229
1249
pub fn subscribe ( & self ) -> Receiver < T > {
1230
1250
let shared = self . shared . clone ( ) ;
1231
- let version = shared. state . load ( ) . version ( ) ;
1251
+ let version = shared. state . load_receiver ( ) . version ( ) ;
1232
1252
1233
1253
// The CLOSED bit in the state tracks only whether the sender is
1234
1254
// dropped, so we do not need to unset it if this reopens the channel.
@@ -1254,7 +1274,7 @@ impl<T> Sender<T> {
1254
1274
/// }
1255
1275
/// ```
1256
1276
pub fn receiver_count ( & self ) -> usize {
1257
- self . shared . ref_count_rx . load ( Relaxed )
1277
+ self . shared . ref_count_rx . load ( Ordering :: Relaxed )
1258
1278
}
1259
1279
}
1260
1280
0 commit comments