[][src]Function tao_of_rust::ch11::thread_sync::thread_safe

pub fn thread_safe()

线程同步

Basic usage: 线程之间传递可变字符

该代码存在数据竞争

use std::thread;
fn main() {
    let mut s = "Hello".to_string();
    for _ in 0..3 {
        thread::spawn(move || {
            s.push_str(" Rust!");
        });
    }
}Run

Basic usage: 使用Rc共享所有权

Rc不能用于多线程共享

use std::thread;
use std::rc::Rc;
fn main() {
    let mut s = Rc::new("Hello".to_string());
    for _ in 0..3 {
        let mut s_clone = s.clone();
        thread::spawn(move || {
            s_clone.push_str(" hello");
        });
   }
}Run

Basic usage: 使用Arc共享所有权

Arc内部不可变,所以报错

use std::thread;
use std::sync::Arc;
fn main() {
    let s = Arc::new("Hello".to_string());
    for _ in 0..3 {
        let s_clone = s.clone();
        thread::spawn(move || {
            s_clone.push_str(" world!");
        });
   }
}Run

Basic usage: 使用RefCell支持内部可变

RefCell没有实现Sync,报错

use std::thread;
use std::sync::Arc;
use std::cell::RefCell;
fn main() {
    let s = Arc::new(RefCell::new("Hello".to_string()));
    for _ in 0..3 {
        let s_clone = s.clone();
        thread::spawn(move || {
            let s_clone = s_clone.borrow_mut();
           s_clone.push_str(" world!");
       });
   }
}Run

Basic usage: 使用Metux

use std::thread;
use std::sync::{Arc, Mutex};
fn main() {
    let s = Arc::new(Mutex::new("Hello".to_string()));
    let mut v = vec![];
    for _ in 0..3 {
        let s_clone = s.clone();
        let child = thread::spawn(move || {
            let mut s_clone = s_clone.lock().unwrap();
            s_clone.push_str(" world!");
       });
       v.push(child);
   }
   for child in v {
        child.join().unwrap();
   }
}Run

Basic usage: 跨线程恐慌“中毒”示例

线程在获得锁之后发生恐慌

use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
    let mutex = Arc::new(Mutex::new(1));
    let c_mutex = mutex.clone();
    let _ = thread::spawn(move || {
        let mut data = c_mutex.lock().unwrap();
        *data = 2;
        panic!("oh no");
   }).join();
   assert_eq!(mutex.is_poisoned(), true);
   match mutex.lock() {
       Ok(_) => unreachable!(),
       Err(p_err) => {
           let data = p_err.get_ref();
           println!("recovered: {}", data);
       }
   };
}Run

Basic usage: 投掷硬币示例

不会死锁

extern crate rand;
use std::thread;
use std::sync::{Arc, Mutex};
fn main() {
    let total_flips = Arc::new(Mutex::new(0));
    let completed = Arc::new(Mutex::new(0));
    let runs = 8;
    let target_flips = 10;
    for _ in 0..runs {
       let total_flips = total_flips.clone();
       let completed = completed.clone();
       thread::spawn(move || {
           flip_simulate(target_flips, total_flips);
           let mut completed = completed.lock().unwrap();
           *completed += 1;
       });
   }
   loop {
       let completed = completed.lock().unwrap();
       if *completed == runs {
           let total_flips = total_flips.lock().unwrap();
           println!("Final average: {}", *total_flips / *completed);
           break;
       }
   }
}
 
fn flip_simulate(target_flips: u64, total_flips: Arc<Mutex<u64>>) {
    let mut continue_positive = 0;
    let mut iter_counts = 0;
    while continue_positive <= target_flips {
        iter_counts += 1;
        let pro_or_con = rand::random();
        if pro_or_con {
           continue_positive += 1;
        } else {
           continue_positive = 0;
       }
   }
   println!("iter_counts: {}", iter_counts);
   let mut total_flips = total_flips.lock().unwrap();
   *total_flips += iter_counts;
}Run

Basic usage: 投掷硬币示例

死锁

extern crate rand;
use std::thread;
use std::sync::{Arc, Mutex};
fn main() {
    let total_flips = Arc::new(Mutex::new(0));
    let completed = Arc::new(Mutex::new(0));
    let runs = 8;
    let target_flips = 10;
    for _ in 0..runs {
       let total_flips = total_flips.clone();
       let completed = completed.clone();
       thread::spawn(move || {
           flip_simulate(target_flips, total_flips);
           let mut completed = completed.lock().unwrap();
           *completed += 1;
       });
   }
   loop {
       let completed = completed.lock().unwrap();
       while *completed < runs {}
       let total_flips = total_flips.lock().unwrap();
       println!("Final average: {}", *total_flips / *completed);
   }
}
 
fn flip_simulate(target_flips: u64, total_flips: Arc<Mutex<u64>>) {
    let mut continue_positive = 0;
    let mut iter_counts = 0;
    while continue_positive <= target_flips {
        iter_counts += 1;
        let pro_or_con = rand::random();
        if pro_or_con {
           continue_positive += 1;
        } else {
           continue_positive = 0;
       }
   }
   println!("iter_counts: {}", iter_counts);
   let mut total_flips = total_flips.lock().unwrap();
   *total_flips += iter_counts;
}Run

Basic usage: 读写锁示例

use std::sync::RwLock;
fn main() {
    let lock = RwLock::new(5);
    {
        let r1 = lock.read().unwrap();
        let r2 = lock.read().unwrap();
        assert_eq!(*r1, 5);
        assert_eq!(*r2, 5);
    } 
   {
       let mut w = lock.write().unwrap();
       *w += 1;
       assert_eq!(*w, 6);
   }
}Run

Basic usage: 屏障示例

use std::sync::{Arc, Barrier};
use std::thread;
fn main() {
    let mut handles = Vec::with_capacity(5);
    let barrier = Arc::new(Barrier::new(5));
    for _ in 0..5 {
        let c = barrier.clone();
        handles.push(thread::spawn(move|| {
            println!("before wait");
           c.wait();
           println!("after wait");
       }));
   }
   for handle in handles {
       handle.join().unwrap();
   }
}Run

Basic usage: 条件变量

use std::sync::{Arc, Condvar, Mutex};
use std::thread;
fn main() {
    let pair = Arc::new((Mutex::new(false), Condvar::new()));
    let pair_clone = pair.clone();
    thread::spawn(move || {
        let &(ref lock, ref cvar) = &*pair_clone;
        let mut started = lock.lock().unwrap();
        *started = true;
       cvar.notify_one();
   });
   let &(ref lock, ref cvar) = &*pair;
   let mut started = lock.lock().unwrap();
   while !*started {
       println!("{}", started); // false
       started = cvar.wait(started).unwrap();
       println!("{}", started); // true
   }
}Run