fntest_relaxed(){println!("Relaxed Ordering");// create a new atomic u32
leta_num=Arc::new(AtomicU32::new(0));leta_num_ref=Arc::clone(&a_num);// create 2 threads
// use relaxed ordering to increment the number
lett1=std::thread::spawn(move||{foriin0..1000000{a_num.store(i,std::sync::atomic::Ordering::Relaxed);}});// use relaxed ordering to print the number, this will be monotonous increment
lett2=std::thread::spawn(move||{for_in0..100{println!("{:}",a_num_ref.load(std::sync::atomic::Ordering::Relaxed))}});t1.join().unwrap();t2.join().unwrap();}
fntest_release_acquire(){println!("Release-Acquire Ordering");letdata=Arc::new(AtomicBool::new(false));letdata_clone=Arc::clone(&data);lett1=std::thread::spawn(move||{// use release ordering to store the data
data.store(true,Ordering::Release);});lett2=std::thread::spawn(move||{// use acquire ordering to load the data
letvalue=data_clone.load(Ordering::Acquire);println!("Value: {}",value);});t1.join().unwrap();t2.join().unwrap();}
It provides the same restrictions and limitation to moving loads around that sequential programmers are inherently familiar with, except it applies across threads.
fntest_seqcst(){println!("Seq-Cst Ordering");// create a new atomic u32
letx=Arc::new(AtomicU32::new(0));lety=Arc::new(AtomicU32::new(0));letyy=Arc::clone(&y);letxx=Arc::clone(&x);lett1=std::thread::spawn(move||{println!("t1: change x to 10, then y to 20");y.store(20,Ordering::SeqCst);x.store(10,Ordering::SeqCst);});letx=Arc::clone(&xx);lety=Arc::clone(&yy);lett2=std::thread::spawn(move||{ifx.load(Ordering::SeqCst)==10{println!("t2: x is 10 and y is 20");assert_eq!(y.load(Ordering::SeqCst),20);println!("t2: change y to 5");y.store(5,Ordering::SeqCst);}});lett3=std::thread::spawn(move||{ifyy.load(Ordering::SeqCst)==5{println!("t3: x is 10 and y is 5");assert_eq!(xx.load(Ordering::SeqCst),10);}});t1.join().unwrap();t2.join().unwrap();t3.join().unwrap();}