Как заблокировать/синхронизировать доступ к переменной в Go во время параллельных горутин?

В своем ответе на этот вопрос: Неустойчивое поведение Golang для Windows? пользователю @distributed рекомендуется заблокировать/синхронизировать доступ к общей переменной в параллельных горутинах.

Как мне это сделать?

Подробнее о проблеме:

Я получаю этот код (возвращенная функция с замыканием на представлениях), работающий на нескольких горутинах одновременно:

func makeHomeHandler() func(c *http.Conn, r *http.Request) {
    views := 1
    return func(c *http.Conn, r *http.Request) {
        fmt.Fprintf(c, "Counting %s, %d so far.", r.URL.Path[1:], views)
        views++
    }
}

Похоже, что функция ввода-вывода принимает пришло время, и в результате я получаю такой вывод:

Counting monkeys, 5 so far.
Counting monkeys, 5 so far.
Counting monkeys, 5 so far.
Counting monkeys, 8 so far.
Counting monkeys, 8 so far.
Counting monkeys, 8 so far.
Counting monkeys, 11 so far.

Он увеличивается нормально, но когда он печатается, я вижу, что операция print+incrementing вовсе не атомарна.

Если я изменю его на:

func makeHomeHandler() func(c *http.Conn, r *http.Request) {
    views := 0
    return func(c *http.Conn, r *http.Request) {
        views++
        // I can only hope that other goroutine does not increment the counter 
        // at this point, i.e., right after the previous line and before the 
        // next one are executed!
        views_now := views
        fmt.Fprintf(c, "Counting %s, %d so far.", r.URL.Path[1:], views_now)
    }
}

Кажется, он работает нормально, но я не совсем уверен, что в конце концов он не выйдет из строя...

14
задан Community 23 May 2017 в 10:29
поделиться