10

For each of the following thread-local storage implementations, how can an external thread-local variable be accessed in Rust programs using the standard ffi mechanisms as exposed by the compiler or standard library?

  • C11
  • gcc's tls extension
  • pthreads
  • Windows TLS API
7
  • 2
    Can you supplement the library and provide a C function to read and write to those thread_local variables? Commented Feb 17, 2017 at 7:05
  • Yes. It's my intention to write a small glue library to deal with thread-local variables if Rust lacks the necessary facilities to do so. However, I prefer to avoid the extra build dependencies if at all possible. Commented Feb 17, 2017 at 8:58
  • 2
    Any answer would require you to tell us what threading system you are using and how you are creating thread local variables. A great way of doing that would be to provide a minimal reproducible example of the extern code and the Rust code that you've created that shows how you'd like to access it. Commented Feb 17, 2017 at 15:11
  • 1
    If the thread local variable is declared as pub you should be able to access it from everywhere. See LocalKey and thread_local or this playground Commented Feb 18, 2017 at 14:02
  • 1
    @Doe Ah yes, I misunderstood. I added an answer with a C11 _Thread_local solution using gcc. Commented Feb 20, 2017 at 13:44

1 Answer 1

9

Rust has a nightly feature, which allows linking to external thread local variables. The stabilization of the feature is tracked here.

C11 / GCC TLS extension

C11 defines the _Thread_local keyword to define thread-storage duration for an object. There also exists a thread_local macro alias.

GCC also implements a Thread Local extension which uses __thread as a keyword.

Linking to both an external C11 _Thread_local and a gcc __thread variable is possible using nightly (tested with rustc 1.17.0-nightly (0e7727795 2017-02-19) and gcc 5.4)

#![feature(thread_local)]

extern crate libc;

use libc::c_int;

#[link(name="test", kind="static")]
extern {
    #[thread_local]
    static mut test_global: c_int;
}

fn main() {
    let mut threads = vec![];
    for _ in 0..5 {
        let thread = std::thread::spawn(|| {
            unsafe {
                test_global += 1;
                println!("{}", test_global);
                test_global += 1;
            }
        });
        threads.push(thread);
    }

    for thread in threads {
        thread.join().unwrap();
    }
}

This allows get access to a variable declared as either of the following:

_Thread_local extern int test_global;
extern __local int test_global;

The output of the above Rust code will be:

1
1
1
1
1

Which is expected, when the variable is defined as thread local.

Sign up to request clarification or add additional context in comments.

1 Comment

Excellent answer. Corresponding tracking issue seems to be github.com/rust-lang/rust/issues/29594. From the issue it seems that stabilization does not seem likely.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.