美文网首页
线程(thread)与 通道(channel)

线程(thread)与 通道(channel)

作者: 简书网abc | 来源:发表于2021-08-30 19:42 被阅读0次

    1. 线程的创建与基本使用

    use std::thread;
    use std::time::Duration;
    
    fn main() {
        // 在子线程里面定义一个闭包
        let handle = thread::spawn(|| {
            for i in 0..10 {
                println!("num {} is in span thread.", i);
                thread::sleep(Duration::from_millis(100));
            }
        });
    
        handle.join().unwrap(); // // 等到线程工作结束
    
        println!("+++++++++++++++++++++++++");
        for i in 1..5 {
            println!("main thread {}", i);
            thread::sleep(Duration::from_millis(10));
        }
        println!("over");
    }
    

    2. move 强制所有权迁移

    use std::thread;
    fn main() {
        let v = vec![1, 2, 3];
    
        //移动 v所有权 到子线程内, 则后面不可在使用
        let handle = thread::spawn(move || {
            println!("v : {:?}", v);
        });
    
        // println!("in main thread, v: {:?}", v);
        handle.join().unwrap();
        println!("over!");
    }
    

    3. 通道的基本使用

    // 通道的基本使用
    use std::thread;
    use std::sync::mpsc;
    
    fn main() {
        let (tx, rx) = mpsc::channel();
    
        thread::spawn(move || {
            let val = String::from("hi");
            tx.send(val).unwrap();
            // println!("val = {}", val); //调用send的时候,会发生move动作,所以此处不能再使用val
        });
        // 这里会发送阻塞, 所以可以不用join
        let received = rx.recv().unwrap();
        println!("Got: {}", received);
    }
    //知识点:
    //1、发送者的send方法返回的是一个Result<T,E>,
    //如果接收端已经被丢弃了,将没有发送值的目标,此时发送会返回错误。
    //2、接受者的recv返回值也是一个Result类型,当通道发送端关闭时,返回一个错误值。
    //3、接收端这里使用的recv方法,会阻塞到有一个消息到来。我们也可以使用try_recv(),不会阻塞,会立即返回。
    
    //1、Rust中一个实现消息传递并发的主要工具是通道。通道由两部分组成,一个是发送端,一个是接收端,发送端用来发送消息,接收端用来接收消息。发送者或者接收者任一被丢弃时就可以认为通道被关闭了。
    //
    //2、通道介绍
    //(1)通过mpsc::channel,创建通道,mpsc是多个生产者,单个消费者;
    //(2)通过spmc::channel,创建通道,spmc是一个生产者,多个消费者;
    //(3)创建通道后返回的是发送者和消费者,示例:
    //let (tx, rx) = mpsc::channel();
    //let (tx, rx) = spmc::channel();
    

    4. 调用send的时候,会发生move动作

    use std::thread;
    use std::sync::mpsc;
    
    fn main() {
        let (tx, rx) = mpsc::channel();
        thread::spawn(move || {
            let val = String::from("ing");
            tx.send(val).unwrap();
            //调用send的时候,会发生move动作,所以此处不能再使用val
            // println!("val = {}", val);
        });
        let re = rx.recv().unwrap();
        println!("got : {}", re);
        println!("over!");
    }
    

    5. 发送多次的例子

    use std::thread;
    use std::sync::mpsc;
    use std::time::Duration;
    
    fn main() {
        let (tx, rx) = mpsc::channel();
    
        thread::spawn(move || {
            let vals = vec![
                String::from("hi"),
                String::from("from"),
                String::from("the"),
                String::from("thread"),
            ];
            // 这里发送多次
            for val in vals {
                tx.send(val).unwrap();
                thread::sleep(Duration::from_secs(1));
            }
        });
    
        // 直接从管道接收.
        for recv in rx {
            println!("got : {}", recv);
        }
        println!("over!");
    }
    

    6. 通过克隆发送者来创建多个生产者, 并使用多个线程发送

    // 多个线程发送的例子
    use std::thread;
    use std::sync::mpsc;
    use std::time::Duration;
    
    fn main() {
        let (tx, rx) = mpsc::channel();
        // 连续克隆两个发送通道
        let tx1 = mpsc::Sender::clone(&tx);
        let tx2 = mpsc::Sender::clone(&tx);
    
        thread::spawn(move || {
            let vals = vec![
                String::from("hi"),
                String::from("from"),
                String::from("the"),
                String::from("thread"),
            ];
    
            for val in vals {
                tx1.send(val).unwrap();
                thread::sleep(Duration::from_secs(1));
            }
        });
    
        thread::spawn(move || {
            let vals = vec![
                String::from("A"),
                String::from("B"),
                String::from("C"),
                String::from("D"),
            ];
    
            for val in vals {
                tx.send(val).unwrap();
                thread::sleep(Duration::from_secs(1));
            }
        });
    
        thread::spawn(move || {
            let vals = vec![
                String::from("a"),
                String::from("b"),
                String::from("c"),
                String::from("d"),
            ];
    
            for val in vals {
                tx2.send(val).unwrap();
                thread::sleep(Duration::from_secs(1));
            }
        });
    
        for rec in rx {
            println!("Got: {}", rec);
        }
    
        println!("Hello, world!");
    }
    

    7. 简单使用互斥器

    //1、通道类似于单所有权的方式,值传递到通道后,发送者就无法再使用这个值;
    //2、共享内存类似于多所有权,即多个线程可以同时访问相同的内存位置。
    
    //互斥器:mutex
    //1、任意时刻,只允许一个线程来访问某些数据;
    //2、互斥器使用时,需要先获取到锁,使用后需要释放锁。
    //Mutex<T>
    
    use std::sync::Mutex;
    
    fn main() {
        let m = Mutex::new(5);
    
        {
            let mut num = m.lock().unwrap();    // 先获取到锁
            *num = 6;
        }//离开作用域时,自动释放
    
        println!("m = {:?}", m);
    }
    
    //Mutex<T>是一个智能指针,lock调用返回一个叫做MutexGuard的智能指针
    //内部提供了drop方法,实现当MutexGuard离开作用域时自动释放锁。
    

    8. 一个复杂的例子 [原子引用计数 Arc<T> ]

    //RefCell\Rc\Box
    
    //RefCell<T>/Rc<T> 与Mutex<T>/Arc<T>
    //1、Mutex<T>提供内部可变性,类似于RefCell
    //2、RefCell<T>/Rc<T>是非线程安全的, Mutex<T>/Arc<T>是线程安全的
    use std::sync::Mutex;
    use std::thread;
    //use std::rc::Rc;
    use std::sync::Arc;
    
    //Arc<T>
    fn main() {
        //let counter = Mutex::new(0);
        //let counter = Rc::new(Mutex::new(0));  //非线程安全
        let counter = Arc::new(Mutex::new(0));
        let mut handles = vec![];
    
        for _ in 0..10 {
            let cnt = Arc::clone(&counter);
            let handle = thread::spawn(move || {
                let mut num = cnt.lock().unwrap();
                *num += 1;
            });
    
            handles.push(handle);
        }
    
        for handle in handles {
            handle.join().unwrap();
        }
    
        println!("resut = {}", *counter.lock().unwrap());
        println!("Hello, world!");
    }
    

    相关文章

      网友评论

          本文标题:线程(thread)与 通道(channel)

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