rust线程

2024-05-26  本文已影响0人  Wu杰语

rust多线程,和erlang非常类似,都使用spawn创建一个线程。例如一个erlang的例子

-module(thread_example).
-export([start/0]).

% 定义要在新线程中执行的函数
print_message() ->
    io:format("Hello from the new thread~n").

% 启动函数
start() ->
    % 使用spawn函数创建一个新的线程,并传递print_message函数
    spawn(fun print_message/0),
    ok.

对比一下rust,可以发现erlang和rust及其相似,rust学习了erlang。

1. rust创建线程

rust使用thread包负责创建线程,spawn定义如下:

pub fn spawn<F, T>(f: F) -> JoinHandle<T> where    F: FnOnce() -> T,    F: Send + 'static,    T: Send + 'static,

一个例子代码:

   let mut handles = vec![];
    
    for i in 0..NTHREADS {
        handles.push(thread::spawn(move || { println!("this is thread number {}", i);}));
    }
    
    println!("waiting for every thread");
    
    for handle in handles {
        handle.join();
    }

例如说这个例子,创建10个线程,每个线程打印一个数字。

1.1 thread::Tread获取线程的id和名字

use std::thread;


// This is the `main` thread
fn main() {
    println!("{:?}", thread::current().id());
    println!("{:?}", thread::current().name());
}

返回:
ThreadId(1)
Some("main")
let handler = thread::spawn(move || {println!("hello")});
prantln!("{:?}", handler.thread().id());
prantln!("{:?}", handler.thread().name());

返回:
ThreadId(2)
None

1.2 thread::Builder(如何给thread命名)

let builder = thread::Builder::new()
    .name("foo".into());

let handler = builder.spawn(|| {
    println!("{:?}", thread::current().name());
}).unwrap();

handler.join().unwrap();

1.3 线程中如何传递共享参数

    let v = Arc::new(Mutex::new(vec![1,2,3]));
    
    let mut handlers = vec![];
    
    for i in 0..3 {
        let clone_v = v.clone();
        handlers.push(thread::spawn(move || {clone_v.lock().unwrap().push(i)}));    
    }
    
    for handler in handlers {
        let _ = handler.join();
    }
    
    println!("{:?}", v.lock().unwrap());

共享参数使用Arc只能指针来传递,Arc是个引用,其指向的值并未被复制。在操作的时候使用Mutex来完成同步。

1.4 thread::park和thread:unpark

use std::thread;
use std::sync::{Arc, atomic::{Ordering, AtomicBool}};
use std::time::Duration;

let flag = Arc::new(AtomicBool::new(false));
let flag2 = Arc::clone(&flag);

let parked_thread = thread::spawn(move || {
    // We want to wait until the flag is set. We *could* just spin, but using
    // park/unpark is more efficient.
    while !flag2.load(Ordering::Acquire) {
        println!("Parking thread");
        thread::park();
        // We *could* get here spuriously, i.e., way before the 10ms below are over!
        // But that is no problem, we are in a loop until the flag is set anyway.
        println!("Thread unparked");
    }
    println!("Flag received");
});

// Let some time pass for the thread to be spawned.
thread::sleep(Duration::from_millis(10));

// Set the flag, and let the thread wake up.
// There is no race condition here, if `unpark`
// happens first, `park` will return immediately.
// Hence there is no risk of a deadlock.
flag.store(true, Ordering::Release);
println!("Unpark the thread");
parked_thread.thread().unpark();

parked_thread.join().unwrap();

注意这里调用thread::park()阻塞的是当前线程,而接触阻塞调用的是handler.thread().unpark()。
另外还有thread::park_timeout()方法,对阻塞设置超时。

小结

thread包封装了比较简洁的方法,提供线程相关的操作,thread包提供了join和park方法完成线程之间的协作;构造了JoinHandler、Builder、Thread、ThreadId等结构,有序的组合除了thread操作。学习thread包,应把doc文档好好看一遍,消化第一手知识,而不要只看文章,看别人消化了加工出的知识。

上一篇 下一篇

猜你喜欢

热点阅读