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.

Billboard image

The fastest way to detect downtimes

Join Vercel, CrowdStrike, and thousands of other teams that trust Checkly to streamline monitoring.

Get started now

Top comments (0)

Image of Timescale

Timescale – the developer's data platform for modern apps, built on PostgreSQL

Timescale Cloud is PostgreSQL optimized for speed, scale, and performance. Over 3 million IoT, AI, crypto, and dev tool apps are powered by Timescale. Try it free today! No credit card required.

Try free

πŸ‘‹ Kindness is contagious

Dive into an ocean of knowledge with this thought-provoking post, revered deeply within the supportive DEV Community. Developers of all levels are welcome to join and enhance our collective intelligence.

Saying a simple "thank you" can brighten someone's day. Share your gratitude in the comments below!

On DEV, sharing ideas eases our path and fortifies our community connections. Found this helpful? Sending a quick thanks to the author can be profoundly valued.

Okay