• Rust Lang Book Ch.16 Concurrency


    使用线程来并行化任务一方面可以加快速度,避免因为IO等待耗费太久时间,另外一方面,也带来了资源竞争,死锁和潜在的难以复现的种种bug。不同的编程语言采取不同策略来生成管理调度线程,如果用户在编程语言中申请一个线程,就通过系统接口获取系统的一个线程,那么就称之为1:1模型。编程语言提供的线程被称为green thread,每M个green threads对应N个系统线程的模型就被称之为M:N模型。为了保证Rust在每个binary上附带的runtime code,即额外需要的用于运行的代码最少,Rust只提供了1:1线程模型。

    thread::spawn

    Rust使用thread::spawn来创建简单的线程JoinHandle,并且可以用JoinHandle::join()来等待所有的线程返回

    use std::thread;
    use std::time::Duration;
    
    fn main() {
        let handle = thread::spawn(|| {
            for i in 1..10 {
                println!("hi number {} from the spawned thread!", i);
                thread::sleep(Duration::from_millis(1));
            }
        });
    
        for i in 1..5 {
            println!("hi number {} from the main thread!", i);
            thread::sleep(Duration::from_millis(1));
        }
    
        handle.join().unwrap();
    }
    

      

    move使得线程能访问另一个线程中的数据

    线程可以使用move来获得另一个线程中拥有的变量(captured variable)的ownership,当然,在move之后,这个变量就不能在原来的线程中使用了。

    use std::thread;
    
    fn main() {
        let v = vec![1, 2, 3];
    
        let handle = thread::spawn(move || {
            println!("Here's a vector: {:?}", v);
        });
    
        handle.join().unwrap();
    }
    

      

    如果尝试继续用,比如试着drop,就会报错:

    use std::thread;
    
    fn main() {
        let v = vec![1, 2, 3];
    
        let handle = thread::spawn(move || {
            println!("Here's a vector: {:?}", v);
        });
    
        drop(v); // oh no!
               ^ value used here after move
        handle.join().unwrap();
    }
    

      

    channel

    channel可以认为有两半:transmitter发送端和receiver接收端。无论是接受还是发送端drop掉了,都可以认为是channel已经关闭了。

     mpsc::channel中的mpsc的包意指multiple producer single consumer,即多个发送者,一个接收者。

    发送端可以使用send方法发送数据,接收端可以使用recv或者try_recv来接收数据。对于send方法来说,接收端已经drop掉了会导致返回错误。recv会阻塞直到接收到数据,同样的,如果发送端已经关闭了就会报错。try_recv则不会阻塞。

    use std::sync::mpsc;
    use std::thread;
    
    fn main() {
        let (tx, rx) = mpsc::channel();
    
        thread::spawn(move || {
            let val = String::from("hi");
            tx.send(val).unwrap();
        });
    
        let received = rx.recv().unwrap();
        println!("Got: {}", received);
    }
    

      

    此外,send会导致ownership的转移,所以send的参数是不能继续用了。

    use std::sync::mpsc;
    use std::thread;
    
    fn main() {
        let (tx, rx) = mpsc::channel();
    
        thread::spawn(move || {
            let val = String::from("hi");
                 --- move occurs because `val` has type `std::string::String`, which does not implement the `Copy` trait
            tx.send(val).unwrap();
                       --- value moved here
            println!("val is {}", val);
                                    ^^^ value borrowed here after move
        });
    
        let received = rx.recv().unwrap();
        println!("Got: {}", received);
    }
    

     

    Shared-State Concurrency

    Mutex<T>+ Arc<T>

    Mutex本身是个Smart Pointer,Mutex::lock返回一个LockResult结构,里面的Smart Pointer结构MutexGuard能够获取指向数据本身的引用,而Drop会自动释放锁。注意在传给不同线程的时候,可以结合Arc(Atomic Reference Counting)一起使用以传递Mutex本身,因为多个线程必须共享同个Mutex对象。此外,Rc不是线程安全的在这里不能用。Mutex与Arc的组合,正如RefCell和Rc的组合,前者提供了interior mutability,后者则分发引用。

    use std::sync::Mutex;
    use std::thread;
    
    fn main() {
        let counter = Arc::new(Mutex::new(0));
        let mut handles = vec![];
    
        for _ in 0..10 {
    let counter = Arc::clone(&counter);
    //这里要给每个
    let handle = thread::spawn(move || { let mut num = counter.lock().unwrap(); *num += 1; }); handles.push(handle); } for handle in handles { handle.join().unwrap(); } println!("Result: {}", *counter.lock().unwrap()); }

      

    Extensible Concurrency with the Sync and Send traits

    Rust语言自身的并发功能很少,大部分并发功能都是在standard library而不是core中实现的。程序员可以通过std::marker中的两个traits Sync和Send来自定义并发功能。Sync和Send都是unsafe的。

    Send特性说明实现了该特性的类型是可以在线程之间交换ownership的。Sync特性则说明它的引用可以安全地发送给其他线程,即可以被多个线程所引用。

  • 相关阅读:
    STL 源代码分析 算法 stl_algo.h -- includes
    Objective-c 算术函数和常量代表
    文件比较,文件夹比较-- vimdiff,beyond compare, compare suite, WinMerge,Kdiff3
    PHP+lghttpd + postgresql 环境搭建
    开源免费跨平台opengl opencv webgl gtk blender, opengl贴图程序
    expect 参数处理之一
    几款屏幕录制软件 ActivePresente
    gcc -D 传值给代码,默认值为1
    error: /usr/include/stdio.h: Permission denied 的一种情况分析
    linux内核编译环境配置
  • 原文地址:https://www.cnblogs.com/xuesu/p/13887552.html
Copyright © 2020-2023  润新知