Что подразумевается под условием гонки в GO при использовании флага -race - PullRequest
0 голосов
/ 19 октября 2018

Рассмотрим следующий код:

package main

import (
    "fmt"
    "sync"
)

func main() {
var a int
m := new(sync.Mutex)

wg := sync.WaitGroup{}
wg.Add(2)

go func(){
    m.Lock()
    a = 2
    m.Unlock()
    wg.Done()
}()

go func(){
    //m.Lock()
    a = 9
    //m.Unlock()
    wg.Done()
}()

wg.Wait()

fmt.Println(a)
}

если мы запустим этот код с флагом -race, мы получим предупреждение о наличии условия гонки.

1) что может пойти не так с этимусловие гонки?

если мы раскомментируем блокировку во второй программе, мы не получим предупреждение о состоянии гонки.Но у нас может быть другой результат, поэтому существует состояние гонки.

2) Почему сейчас у нас нет предупреждения о состоянии гонки?

Ответы [ 2 ]

0 голосов
/ 19 октября 2018

Состояние гонки возникает, когда две или более операций должны выполняться в правильном порядке, но они этого не делают из-за способа написания программы.

гонка данных: одна параллельная операцияпытается прочитать переменную, в то время как в какое-то неопределенное время другая параллельная операция пытается записать в эту же переменную.

В этом простом примере есть гонка данных, так как мы читаем a и печатаем, куда идут другие-программа пытается обновить значение.

package main

import "fmt"

func main() {
    var a int

    go func() {
        a++
    }()

    if a == 0 {
        fmt.Println("data:", a)
    }
}

возможности вывода:

  1. a равно 1, и оно печатается (a равно 0, при вводе блока if, но к моменту его печати он изменился.)
  2. a равен 0, и он печатается (обновление еще не произошло)
  3. ничегонапечатано, (a обновлено)

Возвращаясь к вашему вопросу:

1. что может пойти не так с этим условием гонки?

Ответ:

  1. вывод a не определенd, это может быть 2 или 9. (если ваш первый go func() запускается первым, a будет 9, если второй func() запускается первым, a будет 2).
  2. ваше обновление a в секунду func(), теперь сначала func() запускается и пытается обновить, функция, которая записала в последнюю очередь a, определит вывод. Это может быть 2 или 9 еще раз.
  3. блокировки используются в предположении, что в любое время только одна подпрограмма удерживает ее, и когда у нее есть доступ, никакая другая переменная не записывает в нее, потому что они не получают эксклюзивную блокировку, но если они естьОбщая переменная не защищена блокировкой, поэтому она может обращаться к переменной и вносить необходимые изменения.

2. Почему сейчас у нас нет предупреждения о состоянии гонки?

Ответ:

Потому что теперь в любой момент времени только одна программа может получить доступ к a и обновить его.Но даже сейчас a не является детерминированным, который когда-либо func() запускается последним, определит это.(даже в этом состоянии гонки можно преодолеть это с помощью правильной синхронизации).

-race не может определить этот тип условий race, потому что это почти невозможно сделать.

0 голосов
/ 19 октября 2018

1) что может пойти не так с этим условием гонки?

  • Неопределенное поведение
  • Повреждение памяти
  • аварийно завершает работу. Буквально наихудший из возможных результатов - не знать и потенциально иметь абсолютно недопустимое значение в вашей переменной: p

2) Почему сейчас у нас нетпредупреждение о состоянии гонки?

Mutex - это примитив, который может гарантировать атомарность.Когда блокировка не закомментирована, среда выполнения / операционная система полностью синхронизирует доступ к утверждению (ям), которые блокирует блокировку.т. е. a никогда не будет установлен одновременно на 2 и 9.

Здесь могут быть проблемы с производительностью (ваше приложение может никогда не столкнуться с ними), потому что это сериализованные операции.Обычно это хороший компромисс, поскольку он обеспечивает корректность за счет потенциальных последствий для производительности.


Документация go содержит удивительные ресурсы по конкретным вопросам этой проблемы:

...