Skip to content

Instantly share code, notes, and snippets.

@Grabber
Last active December 6, 2023 23:54
Show Gist options
  • Save Grabber/556674fa180c98f4062bd576476d98b0 to your computer and use it in GitHub Desktop.
Save Grabber/556674fa180c98f4062bd576476d98b0 to your computer and use it in GitHub Desktop.
Golang / sync.WaitGroup / data race investigation with nested structs
package main
import (
"fmt"
"sync"
"time"
)
type Session struct {
Id string
wg *sync.WaitGroup
}
type ClientMessage struct {
Sess *Session
}
func main() {
doneCh := make(chan any)
sess := Session{
Id: "OoOoOoOo",
wg: new(sync.WaitGroup),
}
sess.wg.Add(1)
go func(sess *Session) {
for i := 0; i < 3; i++ {
fmt.Printf("go func(sess *Session): %v -> %d\n", sess, i)
time.Sleep(500 * time.Millisecond)
}
sess.wg.Done()
}(&sess)
cm := ClientMessage{
Sess: &sess,
}
sess.wg.Add(1)
go func(cm *ClientMessage) {
for i := 0; i < 10; i++ {
fmt.Println("loop")
fmt.Printf("go func(cm *ClientMessage): %v -> %d\n", cm.Sess, i)
fmt.Printf("go func(cm *ClientMessage): %v -> %d\n", cm.Sess.Id, i)
time.Sleep(1 * time.Second)
}
cm.Sess.wg.Done()
}(&cm)
cmb := ClientMessage{
Sess: &sess,
}
sess.wg.Add(1)
go func(cm *ClientMessage) {
for i := 0; i < 10; i++ {
fmt.Printf("go func(cm *ClientMessage): %d\n", i)
fmt.Printf("go func(cm *ClientMessage): %v -> %d\n", cm.Sess, i)
time.Sleep(1 * time.Second)
}
cm.Sess.wg.Done()
}(&cmb)
go func(cm *ClientMessage) {
fmt.Println("func(cm *ClientMessage),1")
cm.Sess.wg.Wait()
fmt.Println("func(cm *ClientMessage),2")
doneCh <- struct{}{}
fmt.Println("func(cm *ClientMessage),3")
}(&cm)
fmt.Println("Done,1")
<-doneCh
fmt.Println("Done,3")
}
@Grabber
Copy link
Author

Grabber commented Dec 6, 2023

I found a very interesting data race when using a sync.WaitGroup implace to a nested struct with some gorountines concurrently calling .Done() while another goroutine is waiting on .Wait(). To avoid the race condition, wg must be a pointer and be explicity initialized with new(sync.WaitGroup).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment