Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

go-data-races

Reproducible data-race scenarios of Go. It's based on the Uber blog: Data Race Patterns in Go.

Design

Go's deliberately lightweight concurrency model makes concurrent code easy to write. But easy does not mean simple, ownership and synchronization remain largely the developer's responsibility.

Go developers are often unaware that a variable used inside a closure is a free variable captured by reference, especially when the closure is large. They also frequently use closures as goroutines. As a result, captured variables may be accessed concurrently and without an ordering guarantee unless explicit synchronization is used.

This project demonstrates these risks, their idiomatic fixes and how Java and C++ handle similar situations.

Prerequisites

  • GNU Make and a POSIX shell
  • Go 1.26.x (make check-go refuses any other compiler)
  • JDK/Javac 21 and Maven >= 3.6.3
  • CMake >= 3.16 and a C++20 compiler (g++/clang++)

Commands

Command Purpose
make list list the seven scenarios
make demo SCENARIO_LANG=go PATTERN=01-closure-capture run one scenario demo (go/java/cpp)
make check-go Go 1.26.x gate, build all with -race, run the fixed tests, run the 7 expected-race demos
make check-java build Java, run the 7 Fixed classes, run the jcstress probe (no FORBIDDEN outcome)
make check-cpp CMake/TSan build, run every fixed executable (no race report)
make check-all check-go + check-java + check-cpp
make jcstress visible JCStress litmus run, results kept under artifacts/jcstress/

SCENARIO_LANG selects the demo language (it is not the POSIX LANG variable); PATTERN selects the scenario. An unsafe Go/C++ demo succeeds only when the expected WARNING: DATA RACE (Go) or WARNING: ThreadSanitizer: data race (C++) line is really observed (scripts/run-expected-race.sh).

Scenarios

Every scenario ships a racy unsafe program and a corrected fixed program under scenarios/<pattern>/<lang>/, plus a scenario README. unsafe is caught by a race detector (Go -race, C++ TSan) and fixed runs clean under it.

Java cannot always reproduce the Go traps, due to its design:

  • scenario 01 is prevented at compile time (javac rejects the reassigned capture)
  • scenario 04 is structurally not applicable (Java never copies an Object monitor)
# Pattern What it shows README
01 closure capture a closure reads an outer mutable variable by reference (Go 1.22+ fixed only the loop variable); Java: compile-time prevention README
02 slice sharing copying a slice header shares the backing array; Java: exact README
03 map access concurrent access to a Go map, HashMap, unordered_map; Java: exact README
04 copied lock a value receiver copies the mutex; Java: not applicable; C++: does not compile README
05 signal vs payload the signal (channel/latch) and the payload field are not synchronized together README
06 group synchronization Add/countDown happens after Wait/await started README
07 parallel tests t.Parallel sub-tests mutate shared package state README

References

About

Reproducible data-race scenarios in Go (1.26), based on the Uber blog post: Data Race Patterns in Go.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages