Home >Backend Development >Golang >Is replacing a mapped variable with a new mapped object thread safe?

Is replacing a mapped variable with a new mapped object thread safe?

WBOY
WBOYforward
2024-02-10 16:33:12905browse

Is replacing a mapped variable with a new mapped object thread safe?

php editor Apple is here to answer a common question: "Is it thread-safe to replace a mapping variable with a new mapping object?" Mapping variables are a common data structure. Used to store key-value pairs. In a multi-threaded environment, thread safety is an important consideration. Although using a new mapping object can avoid the problem of concurrent access, whether it is thread-safe still needs to be evaluated on a case-by-case basis. Next, we will explore this issue in depth to help readers better understand the relationship between thread safety and mapped objects.

Question content

I don't think it is thread-safe because the mapped object is larger than the machine word, and golang does not guarantee that it is thread-safe. But when I run the demo code using go run -race main.go it never reports an error. This may be the reason why threadsanitizer relies on runtime checks and assignment operations to find it difficult to satisfy thread unsafe conditions.

Here is the sample code:

package main

import (
    "fmt"
)

var m = make(map[int]bool)

func Read() {
    for {
        for k := range m {
            fmt.Println(k)
        }
    }
}

func Replace() {
    for {
        newM := make(map[int]bool, 10)
        for i := 0; i < 10; i++ {
            newM[i] = false
        }
        m = newM
    }
}

func main() {
    c := make(chan struct{})

    go Read()
    go Replace()

    <-c
}

So how do I modify the code to trigger concurrency errors? Or maybe I'm wrong and the code is thread safe?

Solution

There are a few points to note:

for k := range m {

Range expressions are evaluated once at the beginning of the for loop. So this operation will read m once (note, this means that if the code in the loop reallocates m, the loop will continue to iterate the original m, but If new elements are added or elements are removed from m, these will be detected by the loop), the loop itself will call fmt.println, which will consume most of the execution time in this goroutine . If you want to catch up on the game, delete it.

Second, you don't actually need to initialize the second map.

When you perform these operations and run the race detector, it may catch data races. As far as I'm concerned, it does.

The race detector complains about race when it detects race. So if it reports a match, then there is a match. If it's not reported, it doesn't mean there's no contest.

On my platform, the map variable itself is actually the same size as a machine word: it's just a pointer to the mapped structure. Therefore, writes to mapped variables are effectively atomic, i.e. you will not see partially allocated maps on this platform. However, this does not prevent contention since there is no guarantee when other goroutines will see this memory write.

In short, this is a competition. This is not because of the size of the map variable. To fix this problem, use a mutex.

The above is the detailed content of Is replacing a mapped variable with a new mapped object thread safe?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete