thread_local怎么办!在 Rust 中使用动态库?
How does thread_local! work with dynamic libraries in rust?
正如标题所示,我对共享库如何与 rust 中的线程局部变量一起工作感到困惑。我在下面有一个最小的例子:
在名为 minimal_thread_local_example
的板条箱中:
Cargo.toml:
[package]
name = "minimal_thread_local_example"
version = "0.1.0"
edition = "2018"
[dependencies]
has_thread_local = {path ="./has_thread_local"}
libloading = "0.5"
[workspace]
members = ["shared_library","has_thread_local"]
src/main.rs:
extern crate libloading;
use libloading::{Library, Symbol};
use has_thread_local::{set_thread_local, get_thread_local};
fn main() {
let lib = Library::new("libshared_library.so").unwrap();
set_thread_local(10);
unsafe {
let func: Symbol<unsafe extern fn() -> u32> = lib.get(b"print_local").unwrap();
func();
};
println!("From static executable:{}", get_thread_local());
}
在名为 has_thread_local
的板条箱中:
Cargo.toml:
[package]
name = "has_thread_local"
version = "0.1.0"
edition = "2018"
[lib]
[dependencies]
src/lib.rs:
use std::cell::RefCell;
use std::ops::Deref;
thread_local! {
pub static A_THREAD_LOCAL : RefCell<u64> = RefCell::new(0);
}
pub fn set_thread_local(val: u64) {
A_THREAD_LOCAL.with(|refcell| { refcell.replace(val); })
}
pub fn get_thread_local() -> u64 {
A_THREAD_LOCAL.with(|refcell| *refcell.borrow().deref())
}
在名为 shared_library
的板条箱中:
Cargo.toml:
[package]
name = "shared-library"
version = "0.1.0"
edition = "2018"
[lib]
crate-type = ["cdylib"]
[dependencies]
has_thread_local = {path = "../has_thread_local"}
src/lib.rs:
use has_thread_local::get_thread_local;
#[no_mangle]
unsafe extern "system" fn print_local() {
println!("From shared library:{}",get_thread_local());
}
Here's a github link for the above.
本质上我有一个静态可执行文件和一个共享库,在静态可执行文件中声明了一个线程局部变量。然后我将该变量设置为 10 并从共享库和静态可执行文件访问它。
这输出:
From shared library:0
From static executable:10
我很困惑为什么会输出这个(稳定版和夜间版都会出现)。我本以为两者都是 10,因为本地线程是在静态可执行文件中声明的,并且只能通过也位于该静态可执行文件中的函数访问。我正在寻找关于为什么我观察到这种行为的解释,以及如何使我的本地线程在整个线程中具有相同的值,也就是在共享库和静态库中具有相同的值。
观察到此行为的原因是因为共享库包含它自己的它所依赖的板条箱代码的副本,从而导致两个不同的线程局部声明。
这个问题的解决方案是传递对有问题的线程本地的引用,而不是直接访问线程本地。有关如何获取对本地线程的引用的更多信息,请参见此处:
正如标题所示,我对共享库如何与 rust 中的线程局部变量一起工作感到困惑。我在下面有一个最小的例子:
在名为 minimal_thread_local_example
的板条箱中:
Cargo.toml:
[package]
name = "minimal_thread_local_example"
version = "0.1.0"
edition = "2018"
[dependencies]
has_thread_local = {path ="./has_thread_local"}
libloading = "0.5"
[workspace]
members = ["shared_library","has_thread_local"]
src/main.rs:
extern crate libloading;
use libloading::{Library, Symbol};
use has_thread_local::{set_thread_local, get_thread_local};
fn main() {
let lib = Library::new("libshared_library.so").unwrap();
set_thread_local(10);
unsafe {
let func: Symbol<unsafe extern fn() -> u32> = lib.get(b"print_local").unwrap();
func();
};
println!("From static executable:{}", get_thread_local());
}
在名为 has_thread_local
的板条箱中:
Cargo.toml:
[package]
name = "has_thread_local"
version = "0.1.0"
edition = "2018"
[lib]
[dependencies]
src/lib.rs:
use std::cell::RefCell;
use std::ops::Deref;
thread_local! {
pub static A_THREAD_LOCAL : RefCell<u64> = RefCell::new(0);
}
pub fn set_thread_local(val: u64) {
A_THREAD_LOCAL.with(|refcell| { refcell.replace(val); })
}
pub fn get_thread_local() -> u64 {
A_THREAD_LOCAL.with(|refcell| *refcell.borrow().deref())
}
在名为 shared_library
的板条箱中:
Cargo.toml:
[package]
name = "shared-library"
version = "0.1.0"
edition = "2018"
[lib]
crate-type = ["cdylib"]
[dependencies]
has_thread_local = {path = "../has_thread_local"}
src/lib.rs:
use has_thread_local::get_thread_local;
#[no_mangle]
unsafe extern "system" fn print_local() {
println!("From shared library:{}",get_thread_local());
}
Here's a github link for the above.
本质上我有一个静态可执行文件和一个共享库,在静态可执行文件中声明了一个线程局部变量。然后我将该变量设置为 10 并从共享库和静态可执行文件访问它。
这输出:
From shared library:0
From static executable:10
我很困惑为什么会输出这个(稳定版和夜间版都会出现)。我本以为两者都是 10,因为本地线程是在静态可执行文件中声明的,并且只能通过也位于该静态可执行文件中的函数访问。我正在寻找关于为什么我观察到这种行为的解释,以及如何使我的本地线程在整个线程中具有相同的值,也就是在共享库和静态库中具有相同的值。
观察到此行为的原因是因为共享库包含它自己的它所依赖的板条箱代码的副本,从而导致两个不同的线程局部声明。
这个问题的解决方案是传递对有问题的线程本地的引用,而不是直接访问线程本地。有关如何获取对本地线程的引用的更多信息,请参见此处: