Home > OS >  Any concurrency issues when multiple goroutines access different fields of the same struct
Any concurrency issues when multiple goroutines access different fields of the same struct

Time:10-19

Are there are any concurrency issues if we access mutually exclusive fields of a struct inside different go co-routines?

I remember reading somewhere that if two parallel threads access same object they might get run on different cores of the cpu both having different cpu level caches with different copies of the object in question. (Not related to Go)

Will the below code be sufficient to achieve the functionality correctly or does additional synchronization mechanism needs to be used?

package main

import (
    "fmt"
    "sync"
)

type structure struct {
    x string
    y string
}

func main() {
    val := structure{}
    wg := new(sync.WaitGroup)
    wg.Add(2)
    go func1(&val, wg)
    go func2(&val, wg)
    wg.Wait()
    fmt.Println(val)
}

func func1(val *structure, wg *sync.WaitGroup) {
    val.x = "Test 1"
    wg.Done()
}

func func2(val *structure, wg *sync.WaitGroup) {
    val.y = "Test 2"
    wg.Done()
}

CodePudding user response:

You must synchronize when at least one of accesses to shared resources is a write.

Your code is doing write access, yes, but different struct fields have different memory locations. So you are not accessing shared variables.

If you run your program with the race detector, eg. go run -race main.go it will not print a warning.

Now add fmt.Println(val.y) in func1 and run again, it will print:

WARNING: DATA RACE
Write at 0x00c0000c0010 by goroutine 8:
... rest of race warning

CodePudding user response:

The preferred way in Go would be to communicate memory as opposed to share the memory.

In practice that would mean you should use the Go channels as I show in this blogpost.

https://marcofranssen.nl/concurrency-in-go

If you really want to stick with sharing memory you will have to use a Mutex.

https://tour.golang.org/concurrency/9

However that would cause context switching and Go routines synchronization that slows down your program.

Example using channels

package main

import (
    "fmt"
    "time"
)

type structure struct {
    x string
    y string
}

func main() {
    val := structure{}
    c := make(chan structure)
    go func1(c)
    go func2(c)

    func(c chan structure) {
        for {
            select {
            case v, ok := <-c:
                if !ok {
                    return
                }

                if v.x != "" {
                    fmt.Printf("Received %v\n", v)
                    val.x = v.x
                }
                if v.y != "" {
                    fmt.Printf("Received %v\n", v)
                    val.y = v.y
                }
                if val.x != "" && val.y != "" {
                    close(c)
                }
            }
        }
    }(c)
    fmt.Printf("%v\n", val)
}

func func1(c chan<- structure) {
    time.Sleep(1 * time.Second)
    c <- structure{x: "Test 1"}
}

func func2(c chan<- structure) {
    c <- structure{y: "Test 2"}
}
  •  Tags:  
  • go
  • Related