I'm trying to make a global static COOKIE
(a usize
value) that's valid for as long as there's at least one instance of a GlobalCookie
struct.
So the goal here is that after GlobalCookie::new()
returns:
- The
COOKIE
value will be valid for at least the lifetime of theGlobalCookie
instance. - Each and every
COOKIE
value will need to be cleaned up, but it doesn't really matter when so long as the previous point remains true.
An alternative to using globals here is to create a new cookie for each instance of GlobalCookie
and store the value in each struct. But I do want to avoid (potentially expensive) initialization and cleanup hence I'm using a static COOKIE
and a COUNTER
value to track usage.
It's probably easier if I explain what I mean alongside the code I have so far:
use std::sync::atomic::{AtomicUsize, Ordering};
static COUNTER: AtomicUsize = AtomicUsize::new(0);
static COOKIE: AtomicUsize = AtomicUsize::new(0);
struct GlobalCookie;
// This is the public interface. This ensures that a cookie value exists at
// least as long as there's one instance of `GlobalCookie`. Once every
// `GlobalCookie` has been dropped, then there is no more cookie until a new
// instance is created.
impl GlobalCookie {
pub fn new() -> Self {
let old = COUNTER.fetch_add(1, Ordering::Relaxed);
if old == 0 {
// Create and store a new `COOKIE` value.
let cookie = Self::initialize_cookie();
COOKIE.store(cookie, Ordering::SeqCst);
}
Self {}
}
}
impl Drop for GlobalCookie {
fn drop(&mut self) {
// Store the cookie so I can use it for cleanup if COUNTER drops to zero.
let old_cookie = COOKIE.load(Ordering::SeqCst);
// Decrement the counter and cleanup the cookie if it's zero.
let old_count = COUNTER.fetch_sub(1, Ordering::Relaxed);
if old_count == 1 { // COUNTER is now 0
Self::cleanup_cookie(old_cookie);
}
}
}
My question is, do I need a fence, mutex or other lock around creating and dropping the GlobalCookie
? Or is there a much better way to do this?