"If a worker wants to do his job well, he must first sharpen his tools." - Confucius, "The Analects of Confucius. Lu Linggong"
Front page > Programming > Why is `atomic.StoreUint32` Preferred over Normal Assignment in `sync.Once`?

Why is `atomic.StoreUint32` Preferred over Normal Assignment in `sync.Once`?

Published on 2024-11-12
Browse:501

Why is `atomic.StoreUint32` Preferred over Normal Assignment in `sync.Once`?

Atomic.StoreUint32 vs. Normal Assignment in Sync.Once

In the context of Go's sync.Once, the atomic.StoreUint32 operation is preferred over a normal assignment for setting the done field to 1. This preference stems from the specific semantics and guarantees provided by sync.Once.

Guarantees of Sync.Once

Sync.Once ensures that the function passed to the Do method executes only once. To maintain this guarantee, the done field, which indicates whether the function has already been executed, must be atomically updated.

Limitations of Normal Assignment

If a normal assignment were used (equivalent to o.done = 1), this guarantee could not be assured on architectures with weak memory models. On such architectures, changes made by one goroutine may not be immediately visible to other goroutines, which could lead to multiple goroutines invoking the function in violation of the once-only execution requirement.

Atomic.StoreUint32 Operation

atomic.StoreUint32 is an atomic operation that ensures visibility of the write across all goroutines. By using it to set the done field, sync.Once ensures that all goroutines observe the effect of the function execution before it marks the function as complete.

Scope of Atomic Operations

It's important to note that the atomic operations used in sync.Once are primarily for optimizing the fast path. Access to the done flag outside the mutex synchronized via o.m.Lock() and o.m.Unlock() only needs to be safe, not strictly ordered. This optimization allows for efficient execution on hot paths without sacrificing correctness.

Concurrent Access Considerations

Even though the function execution is protected by the mutex, reading the done field is a data race. Consequently, atomic.LoadUint32 is used to read the field to ensure correct visibility. Likewise, atomic.StoreUint32 is employed to update the field after the function execution, guaranteeing that other goroutines observe the completion of the function before the done flag is set.

In summary, atomic.StoreUint32 is preferred over normal assignment in sync.Once to maintain the guarantee that the function executes only once, even on architectures with weak memory models, due to the atomic visibility it provides. This optimization is applied to enhance performance on the fast path.

Latest tutorial More>

Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.

Copyright© 2022 湘ICP备2022001581号-3