简体   繁体   中英

How does thread_local! work with dynamic libraries in rust?

As the title indicates I'm confused as to how shared libraries work with thread locals in rust. I have a minimal example below:

In a crate called 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());
}

In a crate called 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())
}

In a crate called 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.

In essence I have a static executable and a shared library, with a thread local variable declared in the static executable. I then set that variable to 10 and access it from the shared library and static executable.

This outputs:

From shared library:0
From static executable:10

I'm confused as to why this is outputted(occurs on both stable and nightly). I would have imagined that both would be 10, since the thread local is declared in a static executable and is only accessed via functions also located in that static executable. I'm looking for an explanation as to why I am observing this behavior, and how to make my thread local have the same value across the entire thread, aka have the same value in the shared library and static library.

The reason this behavior is observed is because the shared library contains it's own copy of the code of crates it depends on, resulting in two different thread local declarations.

The solution to this is to pass a reference to the thread local in question, instead of directly accessing the thread local. See here for more information on how to obtain a reference to a thread local: How to create a thread local variable inside of a Rust struct?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM