Reputation: 5025
I am totally new to Go and I am trying to code a game as an exercise.
Basically the main flux will create totalNumberOfPlayers
routines, each of them will perform some tasks following a round-based game. At the end of each round a player is removed from the game until only one player remains.
In order to make sure the routines are synchronized in the same round I am trying to use a WaitGroup
as follows:
func main() {
// ... initialization code
var wg sync.WaitGroup
for i := 0; i < totalNumberOfPlayers; i++ {
go routineJob(i, ..., &wg)
}
// TODO Temporary workaround to let the main flux wait
fmt.Scanln()
}
Each routine runs the same job:
func routineJob(routineId int, ..., wg *sync.WaitGroup) {
// ...
for round := 0; round < totalNumberOfPlayers-1; round++ {
numberOfPlayers := totalNumberOfPlayers - round
wg.Add(1) // Add player to round
// ... perform some tasks
if ... { // Player verifies condition to be removed from the game
wg.Done() // Remove player from round
return
}
// ... perform some other tasks
wg.Done() // Remove player from round
wg.Wait() // Wait for all players to be removed before going to the next round
}
}
But at the end of the first round I get the following error:
panic: sync: WaitGroup is reused before previous Wait has returned
Looking around online I figured out that probably the problem is that after calling wg.Wait()
I am not allowed to call wg.Add(1)
. If that is the case, how can I implement a round based game like this?
Note: I was thinking to create an external WaitGroup
for each round, but that would require me to create another loop somehow in the main()
function and I would prefer to avoid this to keep the structure of the code mostly as presented.
Upvotes: 0
Views: 71
Reputation: 1219
It seems you misunderstand about what sync.WaitGroup used for. Check this
A WaitGroup waits for a collection of goroutines to finish.
When using sync.WaitGroup, I would recommend you add 1 right before using go func() and add defer to mark it as finish right after using go func().
Let assume you are using go routine in main to call routineJob
. So you need to add sync.WaitGroup here first to let your main wait all goroutines finish.
func main() {
// ... initialization code
var wg sync.WaitGroup
for i := 0; i < totalNumberOfPlayers; i++ {
wg.Add(1)
go func(){
// we add 1 for each loop and when the job finish, defer will run which mark added one done.
defer wg.Done()
routineJob(i, ...)
}()
}
wg.Wait()
// no need your work around any more.
fmt.Scanln()
For your routineJob. If there is any go routine that you want to wait, you can apply as the same as above.
func routineJob(routineId int, ...) {
for round := 0; round < totalNumberOfPlayers-1; round++ {
var wg sync.WaitGroup // I assume that you need a list of funcs running in go routine here.
wg.Add(1)
go func() {
defer wg.Done()
// Do your logic....
return
}()
// your go routine 2
wg.Add(1)
go func() {
defer wg.Done()
// Do your logic....
return
}()
wg.Wait() // Wait for all players to be removed before going to the next roundx
}
}
Upvotes: 0