美文网首页
rust 并发

rust 并发

作者: xiongzenghui | 来源:发表于2018-08-12 17:43 被阅读57次

    1、启动子线程

    use std::thread;
    
    fn main() {
      // 启动子线程
      thread::spawn(|| {
        println!("Hello from a thread!");
      });
    
      // 死循环卡住主线程,否则主线程挂掉,上面的子线程也跟着挂掉
      // 也就无法看到子线程的输出
      loop{
      }
    }
    
    ➜  main make
    rustc main.rs
    ./main
    Hello from a thread!
    ^Cmake: *** [all] Interrupt: 2
    
    ➜  main
    

    2、线程异常

    use std::thread;
    
    fn main()
    {
      let result = thread::spawn(move || {
        panic!("oops!");
      }).join();
    
     assert!(result.is_err());
    }
    

    3、同步等待子线程执行完毕

    use std::thread;
    
    fn main() {
      // 启动子线程
      let handle = thread::spawn(|| {
        println!("Hello from a thread!");
        return 99
      });
    
      let ret = handle.join().unwrap();
      println!("ret = {:?}", ret);
    }
    
    ➜  main make
    rustc main.rs
    ./main
    Hello from a thread!
    ret = 99
    ➜  main
    

    4、子线程访问外部数据

    use std::thread;
    
    fn main() 
    {
      let data = vec![1u32, 2, 3];
    
      let handle = thread::spawn(move || {
        println!("data = {:?}", data);
      });
    
      handle.join().unwrap();
    }
    
    ➜  main make
    rustc main.rs
    ./main
    data = [1, 2, 3]
    ➜  main
    

    5、共享可变数据

    1. rust不允许线程修改外部的可变数据

    use std::thread;
    
    fn main() 
    {
      // 可变绑定的数据
      let mut data = vec![1u32, 2, 3];
    
      // 启动3个线程,修改外部的可变数据
      for i in 0..3 {
        thread::spawn(move || {
          data[i] += 1; // 修改外的可变数据
        });
      }
    
      // 卡住主线程
      loop{}
    }
    

    编译报错

    ➜  main make
    rustc main.rs
    error[E0382]: capture of moved value: `data`
      --> main.rs:11:7
       |
    10 |     thread::spawn(move || {
       |                   ------- value moved (into closure) here
    11 |       data[i] += 1; // 修改外的可变数据
       |       ^^^^ value captured here after move
       |
       = note: move occurs because `data` has type `std::vec::Vec<u32>`, which does not implement the `Copy` trait
    
    error: aborting due to previous error
    
    make: *** [all] Error 101
    ➜  main
    

    2. 只有实现Send接口的数据,才能够在线程间转移所有权

    use std::sync::{Arc, Mutex};
    use std::thread;
    
    fn main() 
    {
      // Arc -> Mutex -> Vec
      // Arc 丝线了 Send 接口,所以可以被其他子线程转移所有权
      let data = Arc::new(Mutex::new(vec![1u32, 2, 3]));
    
      // 启动3个线程,修改外部的可变数据
      for i in 0..3 {
        // 先拷贝一份
        let data = data.clone();
    
        // 子线程修改外的可变数据
        thread::spawn(move || {
          // 进入临界区加锁
          let mut data = data.lock().unwrap();
    
          // 修改临界区的数据
          data[i] += 1; 
        });
      }
    
      // 等待线程执行完毕,打印被修改的data数据
      thread::sleep_ms(50);
      println!("data = {:?}", data); 
    
      // 卡住主线程
      loop{}
    }
    
    ➜  main make
    rustc main.rs
    ./main
    data = Mutex { data: [2, 3, 4] }
    ^Cmake: *** [all] Interrupt: 2
    
    ➜  main
    

    6、使用【通道】同步多个线程

    use std::sync::{Arc, Mutex};
    use std::thread;
    use std::sync::mpsc;
    
    fn main() {
      // 在多个线程之间使用的临界数据
      let data = Arc::new(Mutex::new(0u32));
      println!("{:?}", data);
      
      // 对多线程同步的通道
      let (tx, rx) = mpsc::channel(); 
    
      // 启动10个子线程修改临界区数据
      for _ in 0..10 {
        let (data, tx) = (data.clone(), tx.clone());
    
        thread::spawn(move || {
          // 加锁
          let mut data = data.lock().unwrap();
          // 修改临界区数据
          *data += 1;
          // 解锁 => 给通道发送消息,解除阻塞,执行下一个任务
          tx.send(());
          println!("data => {:?}", *data);
        });
      }
    
      // 控制10个子线程按照顺序依次执行
      for _ in 0..10 {
        rx.recv();
      }
    
      println!("{:?}", data);
    }
    

    7、向通道中发送数据

    use std::sync::{Arc, Mutex};
    use std::thread;
    use std::sync::mpsc;
    
    fn main() {
      // 在多个线程之间使用的临界数据
      let data = Arc::new(Mutex::new(0u32));
      println!("{:?}", data);
      
      // 对多线程同步的通道
      let (tx, rx) = mpsc::channel(); 
    
      // 启动10个子线程修改临界区数据
      for _ in 0..10 {
        let tx = tx.clone();
    
        thread::spawn(move || {
          let answer = 42u32;
          tx.send(answer); // 向通道发送数据
        });
      }
    
      // 控制10个子线程按照顺序依次执行
      for _ in 0..10 {
        println!("{:?}", rx.recv().ok().expect("Could not receive answer")); // 从通道读取数据
      }
    }
    
    ➜  main make
    rustc main.rs
    ./main
    Mutex { data: 0 }
    42
    42
    42
    42
    42
    42
    42
    42
    42
    42
    ➜  main
    

    相关文章

      网友评论

          本文标题:rust 并发

          本文链接:https://www.haomeiwen.com/subject/kjasbftx.html