package stm import ( "flag" "sync" ) func testPingPong(n int, afterHit func(string)) { ball := NewBuiltinEqVar(false) doneVar := NewVar(false) hits := NewVar(0) ready := NewVar(true) // The ball is ready for hitting. var wg sync.WaitGroup bat := func(from, to bool, noise string) { defer wg.Done() for !Atomically(func(tx *Tx) any { if doneVar.Get(tx) { return true } tx.Assert(ready.Get(tx)) if ball.Get(tx) == from { ball.Set(tx, to) hits.Set(tx, hits.Get(tx)+1) ready.Set(tx, false) return false } return tx.Retry() }).(bool) { afterHit(noise) AtomicSet(ready, true) } } wg.Add(2) go bat(false, true, "ping!") go bat(true, false, "pong!") Atomically(VoidOperation(func(tx *Tx) { tx.Assert(hits.Get(tx) >= n) doneVar.Set(tx, true) })) wg.Wait() } var nFlag = flag.Int( "n", 1_000, "The number of iterations to execute", ) func MainTest() { flag.Parse() n := *nFlag var wg sync.WaitGroup wg.Add(n) for i := 0; i < n; i++ { go func() { defer wg.Done() testPingPong(n, func(string) {}) }() } wg.Wait() }