Is it thread safe to access different members of struct in go?
Asked Answered
T

1

27

Is it safe to access different struct members from different goroutines?

I understand that writing to the same variable without sync is dangareous:

package main

type Apple struct {
    color string
    size  uint
}

func main() {
    apple := &Apple{}
    go func() {
        apple.color = "red"
    }()
    go func() {
        apple.color = "green"
    }()
}

But can you write to different struct members without any kind of synchronization?

package main

type Apple struct {
    color string
    size  uint
}

func main() {
    apple := &Apple{}
    go func() {
        apple.color = "red"
    }()
    go func() {
        apple.size = 42
    }()
}

Or should I use chan or sync.Mutex for that?

Trotyl answered 7/4, 2015 at 16:35 Comment(0)
M
38

It should be safe to access different variables from different threads, and struct members are different variables. So yes it should be safe.

However, it may not be fast. Variables that are close together in memory like struct members are will share a CPU cache line. A cache line is the smallest piece of memory that a CPU (well, most current models) can lock. That means that CPU-2 has to wait to write until CPU-1 has finished with that cache line even if they are writing to different variables.

It is NOT safe to change the pointer to the struct while writing to the struct from different threads. In your example if you had a third goroutine that did apple = &Apple{} some of the other goroutines in other threads might write to the old Apple or the new Apple and you wouldn't know.

Memorialist answered 7/4, 2015 at 17:12 Comment(9)
Paragraphs 1 and 3 are great; paragraph 2 seems off-topic (because the concern is safety) and poor advice (because Go is such a high level language, you should write the most expressive code by default, and optimize where needed on a case-by-case basis--not by applying this rationale generally. There's no guarantee that these goroutines will even be executed by different CPUs!).Bruyn
Agree with @weberc2. While false sharing is a concern, the question is about modifying 2 variables with or without a mutex. The cache line problem with be present regardless of which answer is correct, and the solution would be the same regardless.Crony
@weberc2: Funny, because one of the reasons I like Go is because it isn't such a high level language. It compiles much like C with garbage collection.Memorialist
Zan, so struct members are different variables that share nothing with struct itself? Any docs as a reference?Trotyl
@ZanLynx *garbage collection and a goroutine scheduler, which is the key detail here--goroutines don't guarantee parallelism: blog.golang.org/concurrency-is-not-parallelism. It simply doesn't make sense to concern oneself with cache line sharing before one even knows if one's goroutines are executing in parallel; this is premature optimization.Bruyn
@ThunderCat I think this is a parallelism concern; not a concurrency concern. Usually by default, we write Go code with concurrency in mind, and we let the scheduler make parallel decisions for us. If you need to squeeze out extra performance, you can optimize for your use case, but your optimization will likely not be portable across compilers, operating systems, and architectures. Even then, you need to make sure you're actually executing in parallel. In summary, paragraph 2 seems like a footnote of a footnote at best. The word 'may' in its first sentence can't be overemphasized.Bruyn
@KamilDziedzic Struct members occupy distinct segments of memory. If you change distinct memory segments from different threads, there is no conflict. I don't have any resources on hand, but you can Google 'C struct memory layout' (or something like that) and get more information (Go's memory layout is very similar to C, as far as I know).Bruyn
Are struct members really different objects tho? Seems like two different goroutines can modify struct fields at the same timeMonetary
"Unsynchronized, concurrent access to any variable from multiple goroutines where at least one of them is a write is undefined behavior" - this is just insaneMonetary

© 2022 - 2024 — McMap. All rights reserved.