"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > Por que o `sync.Once` do Go usa `atomic.StoreUint32` em vez da atribuição normal para definir o sinalizador `done`?

Por que o `sync.Once` do Go usa `atomic.StoreUint32` em vez da atribuição normal para definir o sinalizador `done`?

Publicado em 2024-11-25
Navegar:895

Why does Go\'s `sync.Once` use `atomic.StoreUint32` instead of normal assignment to set the `done` flag?

Uso adequado de operações atômicas na sincronização do Go.Uma vez

No contexto da sincronização do Go.Uma vez implementada, é crucial entender o distinção entre atribuição normal e a operação atomic.StoreUint32 ao definir o sinalizador concluído.

O Incorreto Implementação

Inicialmente, a função Do em once.go utilizou a seguinte abordagem:

if atomic.CompareAndSwapUint32(&o.done, 0, 1) {
    f()
}

Esta implementação falha em garantir que a execução de f seja completada após o retorno de Do. Duas chamadas simultâneas para Do podem resultar na primeira chamada chamando f com sucesso, enquanto a segunda chamada retorna prematuramente, acreditando que f terminou, mesmo que não tenha terminado.

Operação de armazenamento atômico

Para resolver esse problema, Go emprega a operação atomic.StoreUint32. Ao contrário da atribuição normal, atomic.StoreUint32 garante a visibilidade do sinalizador concluído atualizado para outras goroutines. não é influenciado principalmente pelo modelo de memória da máquina subjacente. O modelo de memória do Go atua como uma abstração unificadora, garantindo um comportamento consistente em diferentes plataformas de hardware, independentemente de seus modelos de memória específicos.

Fast Path otimizado

Para otimizar o desempenho, sincronize .Once emprega um caminho rápido para cenários comuns em que o sinalizador concluído já está definido. Este caminho rápido usa atomic.LoadUint32 para verificar o sinalizador concluído sem adquirir o mutex. Se o sinalizador for definido, a função retorna imediatamente.

Slow Path com Mutex e Atomic Store

Quando o caminho rápido falha (ou seja, feito é inicialmente não definido), o caminho lento é inserido. Um mutex é adquirido para garantir que apenas um chamador possa executar f. Depois que f for concluído, atomic.StoreUint32 é usado para definir o sinalizador concluído, tornando-o visível para outras goroutines.

Leituras simultâneas

Mesmo que o sinalizador concluído esteja definido atomicamente, não torna seguras as leituras simultâneas. A leitura do sinalizador fora da seção crítica protegida requer o uso de atomic.LoadUint32. No entanto, leituras diretas dentro da seção crítica são seguras devido ao mutex fornecer exclusão mútua. memória subjacente モデル e para evitar corridas de dados. A combinação de operações atômicas e mutexes fornece otimizações de desempenho e garantias de correção.

Tutorial mais recente Mais>

Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.

Copyright© 2022 湘ICP备2022001581号-3