Структура golang с одновременным чтением и записью без блокировки также работает нормально?

concurrentMap() есть функция WARNING: DATA RACE, и фатальная ошибка: concurrent map read and map write

concurrentStruct() есть ПРЕДУПРЕЖДЕНИЕ: DATA RACE, но работает нормально

почему структура может DATA RACE?

package main

import (
    "sync"
)

func main() {
    // concurrentMap()
    concurrentStruct()
    // concurrentStructWithMuLock()
}

type Metadata struct {
    mu  sync.RWMutex // ????
    key bool
}

// concurrentStruct 并发操作结构体
// concurrent read and write the struct
// go run -race  main.go   有 WARNING: DATA RACE,但是可以运行
// go run -race  main.go   It have WARNING: DATA RACE, But running ok
func concurrentStruct() {
    m := new(Metadata)

    for i := 0; i < 100000; i++ {
        go func(metadata *Metadata) {
            for {
                readValue := metadata.key
                if readValue {
                    metadata.key = false
                }
            }
        }(m)

        go func(metadata *Metadata) {
            for {
                metadata.key = true
            }
        }(m)
    }

    select {}
}

// concurrentStructWithMuLock  并发操作(使用了读写锁)结构体
// concurrent read and write the struct with RWMutex
// go run -race  main.go   没有 WARNING: DATA RACE
// go run -race  main.go   Don't have WARNING: DATA RACE, and running ok
func concurrentStructWithMuLock() {
    m := new(Metadata)

    go func(metadata *Metadata) {
        for {
            metadata.mu.Lock()
            readValue := metadata.key
            if readValue {
                metadata.key = false
            }
            metadata.mu.Unlock()
        }
    }(m)

    go func(metadata *Metadata) {
        for {
            metadata.mu.Lock()
            metadata.key = true
            metadata.mu.Unlock()
        }
    }(m)

    select {}
}

// concurrentMap 并发读写 Map
// concurrent read and write the map
// go run -race  main.go   有 WARNING: DATA RACE,不可运行,fatal error: concurrent map read and map write
// go run -race  main.go  Have WARNING: DATA RACE, And fatal error: concurrent map read and map write
func concurrentMap() {
    m := make(map[int]int)
    go func() {
        for {
            _ = m[1]
        }
    }()
    go func() {
        for {
            m[2] = 2
        }
    }()
    select {}
}

person Fish    schedule 12.07.2018    source источник


Ответы (1)


Несинхронизированный одновременный доступ к любой переменной из нескольких горутин, где хотя бы одна из них является записью, является неопределенным поведением. Не пытайтесь найти логику в неопределенном поведении, просто используйте правильную синхронизацию. Неопределенный означает, что он может работать "правильно" или может работать "неправильно" (давая неправильные результаты), или может произойти сбой или что-то еще. Вот что значит неопределенный. Узнайте больше об этом здесь: Безопасно ли одновременное чтение указателя функции без блокировки?

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

А с concurrentMap() это другая проблема. В Go 1.6 добавлено облегченное одновременное неправильное использование обнаружения карт в среде выполнения:

В среду выполнения добавлено легкое обнаружение одновременного неправильного использования карт. Как всегда, если одна горутина записывает в карту, ни одна другая горутина не должна одновременно читать или записывать карту. Если среда выполнения обнаруживает это условие, она выводит диагноз и завершает работу программы. Лучший способ узнать больше о проблеме – запустить программу под детектор расы, который более надежно определит расу и даст больше деталей.

Так что это преднамеренный сбой среды выполнения, потому что она обнаруживает несинхронизированный доступ к карте. Это «функция» среды выполнения Go, и она приводит к сбою вашего приложения, потому что в вашем приложении не должно быть гонок данных (во избежание неопределенного поведения). Подробнее об этом читайте здесь: Как восстановить одновременную запись карты?

person icza    schedule 12.07.2018