How do I test if a thread_local value has been initialized without actually initializing it

I have tracing initialization code as follows.

pub fn make_dispatch() -> (Dispatch, WorkerGuard) {
    let file_appender;
    if let Ok(tracefile) =  env::var("WISK_TRACEFILE") {
        file_appender = tracing_appender::rolling::never("", tracefile)
    } else {
        file_appender = tracing_appender::rolling::never("", "/dev/null")
    }
    let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
    let subscriber = FmtSubscriber::builder()
        .with_max_level(Level::TRACE)
        .with_writer(non_blocking)
        .finish();
    (Dispatch::new(subscriber), guard)
}

thread_local!(static MY_DISPATCH: (Dispatch, WorkerGuard) = make_dispatch());

Which is then used

MY_DISPATCH.with(|(my_dispatch, _guard)| { ........... });

But in this case, I don't actually want to initialized a thread_local instance of my_dispatch.
I only want to check if the value is initialized or not.
Something like

if MY_DISPATCH.initialized() {
   // do somethig
} else {
   // something else
}

How do I do that?

Also I don't see ay example of MY_DISPATCH.try_with. Any pointers?

Sadly the API of the object created by the thread_local! macro magic, a LocalKey does indeed not showcase such an initialized(&'static self) -> bool function.

I would suggest doing the following:

thread_local! {
    #[allow(nonstandard_style)]
    static MY_DISPATCH_initialized: ::core::cell::Cell<bool> = false.into();
}
thread_local! {
    static MY_DISPATCH: (Dispatch, WorkerGuard) = {
        let ret = make_dispatch();
        MY_DISPATCH_initialized.with(|it| it.set(true));
        ret
    };
}

so as to do:

if MY_DISPATCH_initialized.with(Cell::get) {
    // do something
} else {
    // something else
}

Just the documentation of LocalKey pointed above. Given their mention of thread_local storage trying to be dropped when the thread dies, it means that if multiple thread locals refer to each other on drop, one of them may stumble upon a dead / dropped / dangling thread local. In that case, try_with() let's you prevent the panic that would occur if with() was used instead.

  • This is indeed important, in that if a thread panics, it will nevertheless run the destructors of the different things in scope, including the thread locals. So if then, during this general panic, the Drop impl of some thread local panics itself too, the program itself will abort: catch_unwind won't be able to recover from that inner panic, and this abort will thus stop all the other threads too, which is contrary to the "panics stop at a thread boundary" model of Rust.
1 Like

Thanks. That helped.
This is a certainly a use case for thread_local variables, that would be nice if it ca be addressed.
Would certainly simplify the code in my usecase.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.