Rust 中的 thread_local

原创
2021/03/27 23:01
阅读数 398

如果要实现一个进程内的缓存,则可以简单的使用一个全局Map, 加上锁来实现。如果每个线程需要有自己的数据,且线程之间的数据不相互影响,全局map的方式就不太好,此种方式会有锁开销,也比较容易出现由于误操作导致线程之间的数据污染。

这时线程本地数据 thread_local就派上用场了,Java中的spring 就使用thread_local 来实现每个线程有独立的事务。

Rust中也对thread_local 有支持,但Rust中使用thread_local稍微有点繁琐. Rust中基于 LocalKey来实现,访问thread_local中的变量,需要通过LocalKey.with 或LocalKey.try_with来访问,以下是使用例子

use std::borrow::Borrow;
use std::cell::Cell;
use std::cell::RefCell;
use std::thread;
use std::thread::LocalKey;

struct Data {
    id: usize
}
thread_local! {
    static FOO: RefCell<Data> = RefCell::new(Data{id:0});
}
fn main() {
    let mut threads = vec![];
    for i in 0 .. 10 {//生成10个子线程,每个子线程中都修改FOO数据
        let join_handler = std::thread::spawn(move || {
            FOO.with(|e| {
                *(e.borrow_mut()) = Data { id: i };
                println!("sub thread id is {}", e.borrow().id);
                assert_eq!(i, e.borrow().id);
            });
        });
        threads.push(join_handler);
    }
    FOO.with(|e| {// 主线程中修改FOO数据
        *(e.borrow_mut()) = Data { id: 100 };
        println!("main thread id is {}", e.borrow().id);
        assert_eq!(100, e.borrow().id);
    });

    while let Some(sub_thread) = threads.pop() {
        sub_thread.join();
    }
    println!("process exit")
}

运行结果显示,每个线程中的FOO数据都不受影响。

thread_local中定义的变量名FOO类型为LocalKey,要访问thread_local中包裹的数据,需要调用with/try_with方法,他们的签名如下

pub fn with<F, R>(&'static self, f: F) -> R where
    F: FnOnce(&T) -> R

pub fn try_with<F, R>(&'static self, f: F) -> Result<R, AccessError> where
    F: FnOnce(&T) -> R

另外需要注意的是:

thread_local中声明的变量,在线程结束后会被释放,比如如果有10个线程中使用了该thread_local变量,则这10个线程结束时将有10个该类型的变量被释放(注:不是任何类型的变量都能被调用drop,每个平台会有一些变量类型无法调用drop)

API详细说明见API文档 https://doc.rust-lang.org/std/thread/struct.LocalKey.html

 

 

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部