Define and enforce atomicity as an explicit contract: if correctness depends on thread/writer invariants, encode it in the API name/docs and validate it at usage sites; if a value can be concurrently updated, read/write it exclusively via atomic operations (no non-atomic peeking into parts of an atomic container).
Practical rules: 1) Single-writer “atomic” helpers
...SingleWriter...), and ensure no other thread can ever update the same variable.2) Packed atomic bitfields
atomic_flags_refcount) as atomic.atomicGet (or equivalent) before masking/shifting; don’t read the underlying integer non-atomically from another thread.3) Document IO-thread vs main-thread invariants
Example (atomic-packed refcount access):
#define OBJ_REFCOUNT_MASK ((1U << OBJ_REFCOUNT_BITS) - 1)
#define OBJ_EXPIRABLE_BIT 30
#define OBJ_ISKVOBJ_BIT 31
static inline unsigned robj_refcount(const robj *o) {
uint32_t v;
atomicGet(o->atomic_flags_refcount, v); // must be atomic
return v & OBJ_REFCOUNT_MASK;
}
static inline unsigned robj_expirable(const robj *o) {
uint32_t v;
atomicGet(o->atomic_flags_refcount, v); // must be atomic
return (v >> OBJ_EXPIRABLE_BIT) & 1;
}
If you can’t clearly state the invariants and make every concurrent access atomic-safe, redesign the ownership model or synchronization rather than relying on “it never races” assumptions.
Enter the URL of a public GitHub repository