Possible to drop the weak reference here?

use std::mem::take;

use std::sync::{Arc, Mutex, Weak, LazyLock};

#[derive(Debug, Default, Clone, Copy)]
struct K;

static G: LazyLock<Vec<Mutex<Arc<K>>>> = LazyLock::new(
    || vec![Mutex::new(Arc::new(K{}))]
);

fn ll() -> std::sync::Weak<K> {
    Arc::downgrade(&G[0].lock().unwrap())
}

thread_local! {
    static L: LazyLock<std::sync::Weak<K>> = LazyLock::new(|| ll());
}

fn d() {
    take(&mut *G[0].lock().unwrap());
    drop(**G[0].lock().unwrap())
}

fn main(){
    d();
    
    let t = std::thread::spawn(|| L.try_with(|l| {
    
        let u =  l.upgrade();
        if u.is_none() {
            println!("invalid")
        } else {
            println!("valid {:?}", u)
        }
        
        
    }));
    
    t.join();
}


(Playground)

Output:

valid Some(K)

Errors:

   Compiling playground v0.0.1 (/playground)
warning: unused import: `Weak`
 --> src/main.rs:3:29
  |
3 | use std::sync::{Arc, Mutex, Weak, LazyLock};
  |                             ^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing
  --> src/main.rs:22:5
   |
22 |     drop(**G[0].lock().unwrap())
   |     ^^^^^----------------------^
   |          |
   |          argument has type `K`
   |
   = note: use `let _ = ...` to ignore the expression or result
   = note: `#[warn(dropping_copy_types)]` on by default

warning: unused `Result` that must be used
  --> src/main.rs:40:5
   |
40 |     t.join();
   |     ^^^^^^^^
   |
   = note: this `Result` may be an `Err` variant, which should be handled
   = note: `#[warn(unused_must_use)]` on by default
help: use `let _ = ...` to ignore the resulting value
   |
40 |     let _ = t.join();
   |     +++++++

warning: `playground` (bin "playground") generated 3 warnings (run `cargo fix --bin "playground"` to apply 1 suggestion)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.64s
     Running `target/debug/playground`

Can you expand a bit on what you're trying to achieve here? I don't understand enough of your goal to make any suggestions, but the control flow is a bit convoluted here and I can help untangle that for you.

Roughly, the sequence of actions that's happening is:

  1. Inside d(), G is accessed for the first time, so the LazyLock creates a 1-element vector
  2. take(&mut *G[0].lock().unwrap()); Locks the mutex in element 0, removes the Arc, and replaces it with a newly-constructed one via Arc::default(), which in turn calls K::default(). The original Arc and K are dropped at the end of the statement.
  3. drop(**G[0].lock().unwrap()) makes a copy of K and then drops the copy, which does nothing other than generating a warning
  4. You spawn a new thread and then immediately join it, so nothing will happen concurrently on the main thread while it executes
  5. Inside the new thread, L.try_with(...) initializes the variable by calling ll(), which generates a Weak pointing to the new Arc<K> that was created in step 2.
  6. The l.upgrade() succeeds because that Arc hasn't been dropped since the Weak was created
  7. When the thread exits, the LocalKey is dropped, and the Weak it contains along with it
  8. join() now returns, allowing the main thread to continue its work.

I'm trying to feed thread-local caches from a global cache and signal the local caches to reload once their weak reference to the global has been dropped. This code is just an attempt to verify the idea is possible. You say in 6 that the upgrade succeeds because that Arc hasnt been dropped since the Weak was created. That makes sense. I thought the opposite.

getting rid of the lazylock for L works