Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is getting a value using range not thread-safe in Go?

Tags:

go

map

When ranging over a map m that has concurrent writers, including ones that could delete from the map, is it not thread-safe to do this?:

for k, v := range m { ... }

I'm thinking to be thread-safe I need to prevent other possible writers from changing the value v while I'm reading it, and (when using a mutex and because locking is a separate step) verify that the key k is still in the map. For example:

for k := range m {
    m.mutex.RLock()
    v, found := m[k]
    m.mutex.RUnlock()
    if found {
        ... // process v
    }
}

(Assume that other writers are write-locking m before changing v.) Is there a better way?

Edit to add: I'm aware that maps aren't thread-safe. However, they are thread-safe in one way, according to the Go spec at http://golang.org/ref/spec#For_statements (search for "If map entries that have not yet been reached are deleted during iteration"). This page indicates that code using range needn't be concerned about other goroutines inserting into or deleting from the map. My question is, does this thread-safe-ness extend to v, such that I can get v for reading only using only for k, v := range m and no other thread-safe mechanism? I created some test code to try to force an app crash to prove that it doesn't work, but even running blatantly thread-unsafe code (lots of goroutines furiously modifying the same map value with no locking mechanism in place) I couldn't get Go to crash!

like image 882
user1744397 Avatar asked Oct 17 '12 15:10

user1744397


People also ask

Is array thread-safe in Golang?

Immutable arrays (declared using let) are thread-safe since it is read-only. But mutable arrays are not thread-safe.

Is Golang map concurrent safe?

It's important to note that maps in go are not safe for concurrent use. Maps are not safe for concurrent use: it's not defined what happens when you read and write to them simultaneously.

Are sync maps thread-safe?

By design, sync. Map is thread safe. sync. Map is a special purpose map with limited uses.

Is appending thread-safe?

Appending a file from multiple threads is not thread-safe and will result in overwritten data and file corruption. In this tutorial, you will explore how to append to a file from multiple threads. Let's dive in.


1 Answers

No, map operations are not atomic/thread-safe, as the commenter to your question pointed to the golang FAQ “Why are map operations not defined to be atomic?”.

To secure your accessing it, you are encouraged to use Go's channels as a means of resource access token. The channel is used to simply pass around a token. Anyone wanting to modify it will request so from the channel - blocking or non-blocking. When done with working with the map it passes the token back to the channel.

Iterating over and working with the map should be sufficiently simple and short, so you should be ok using just one token for full access.

If that is not the case, and you use the map for more complex stuff/a resource consumer needs more time with it, you may implement a reader- vs writer-access-token. So at any given time, only one writer can access the map, but when no writer is active the token is passed to any number of readers, who will not modify the map (thus they can read simultaneously).

For an introduction to channels, see the Effective Go docs on channels.

like image 116
Kissaki Avatar answered Oct 25 '22 06:10

Kissaki