From the description of AtomicUsize's fetch_max, it seems like the return value should always be smaller than or equal to the argument passed to the val parameter.
However, consider the following code:
use rand::Rng; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; use std::time::Duration; const fn generate_bools() -> [bool; 100] { // An array of false values, except for certain indexes. let mut bools = [false; 100]; bools[2] = true; bools[7] = true; bools[12] = true; bools[14] = true; bools[22] = true; bools[30] = true; bools[36] = true; bools[41] = true; bools[43] = true; bools[53] = true; bools[56] = true; bools[63] = true; bools[72] = true; bools[79] = true; bools[82] = true; bools } const BOOLS: [bool; 100] = generate_bools(); fn main() { let counter = Arc::new(AtomicUsize::new(0)); // Spawn 10 threads, for counter increments of +1 to +10 inclusively. for inc in 1..=10 { let counter = counter.clone(); std::thread::spawn(move || loop { // Load the current counter and add the increment for this thread. let current = counter.load(Ordering::SeqCst); let new = current + inc; // Wait for a random duration between 100 and 355 ms. let random = rand::thread_rng().gen::<u8>() + 100; std::thread::sleep(Duration::from_millis(random as u64)); // If the array is true at that index, "fetch_max" it! let is_true = BOOLS[new]; if is_true { let old = counter.fetch_max(new, Ordering::SeqCst); println!("old: {:02} / new: {:02}", old, new); } std::thread::sleep(Duration::from_secs(1)); }); } // Put main thread to sleep for 60s to give time for the children threads. std::thread::sleep(Duration::from_secs(60)); } When I run it, I get unexpected results. Here are two samples:
old: 00 / new: 02 old: 02 / new: 07 old: 07 / new: 14 old: 14 / new: 22 old: 22 / new: 30 old: 30 / new: 36 old: 36 / new: 43 old: 43 / new: 53 old: 53 / new: 63 old: 63 / new: 72 old: 72 / new: 56 <-- old: 72 / new: 79 old: 79 / new: 82 old: 00 / new: 02 old: 02 / new: 07 old: 07 / new: 12 old: 12 / new: 14 old: 14 / new: 22 old: 22 / new: 30 old: 30 / new: 36 old: 36 / new: 43 old: 43 / new: 41 <-- old: 43 / new: 53 old: 53 / new: 56 old: 56 / new: 63 old: 63 / new: 63 old: 63 / new: 72 old: 72 / new: 79 old: 79 / new: 82 I understand that the "new" values might not always go up, because there might be a race condition with the fetch_max and println! statements. For example, thread A can do the fetch_add, then thread B can do the fetch_add and the println!, then thread A can do the println!.
What I don't understand is how the old value can be strictly greater than the new value!
没有评论:
发表评论