DEV Community

Cover image for GO:lack of synchronization
mridul037
mridul037

Posted on

GO:lack of synchronization

var a string
var done bool

func setup() {
    a = "hello, world"
    done = true
}

func doprint() {
    if !done {
        once.Do(setup)
    }
    print(a)
}

func twoprint() {
    go doprint()
    go doprint()
}
Enter fullscreen mode Exit fullscreen mode

Code Analysis

Variables:

  • a and b are global variables of type int, shared by all goroutines.

Functions:

  • f():
    • Writes to a and b sequentially (a = 1 and b = 2).
  • g():
  • Reads and prints b followed by a.

Concurrency in main():

  • The function f() is executed as a separate goroutine using go f().
  • The function g() is executed directly in the main goroutine.

Potential Issues:

  • The goroutine running f() and the main goroutine executing g() run concurrently.
  • The writes to a and b in f() may not complete before g() reads and prints the values of a and b.
  • This introduces a data race, where concurrent access (writes in f() and reads in g()) occurs on shared memory (a and b) without synchronization.

Possible Outcomes
Due to the lack of synchronization, the program's output is non-deterministic. Here are the possible scenarios:

Case 1: g() executes before f() modifies a and b:

  • Initial values of a and b are 0 (default for uninitialized int in Go).
0
0

Enter fullscreen mode Exit fullscreen mode

or

CASE 2: If b = 2 is completed before g() but a = 1 is not, the output could be:

2
0
Enter fullscreen mode Exit fullscreen mode

Key Observations
Data Race: The concurrent access to a and b without synchronization introduces a data race. This makes the program's behavior undefined and unpredictable

Fixing the Code

  1. Using a sync.WaitGroup: Ensure f() completes before g() executes
var a, b int
var wg sync.WaitGroup

func f() {
    a = 1
    b = 2
    wg.Done()
}

func g() {
    print(b)
    print(a)
}

func main() {
    wg.Add(1)
    go f()
    wg.Wait()
    g()
}

Enter fullscreen mode Exit fullscreen mode
  1. Using Channels: Signal when f() is done:
var a, b int

func f(done chan bool) {
    a = 1
    b = 2
    done <- true
}

func g() {
    print(b)
    print(a)
}

func main() {
    done := make(chan bool)
    go f(done)
    <-done
    g()
}

Enter fullscreen mode Exit fullscreen mode

Here, g() waits until f() sends a signal over the done channel.

Top comments (0)