My goal is to use goroutines and channel, i want to learn how to communicate between different goroutines and i want to avoid deadlock. I managed to use sync.WaitGroup and it is working just fine.
However I received an error saying that
1 panic: sync: negative WaitGroup counter
goroutine 19 [running]:
The goal of this program is simple.
The code:
package main
import (
"fmt"
"sync"
"time"
)
type developer struct {
name string
setTimeForWebsite time.Time
}
type website struct {
owner string
created time.Time
}
var developers []developer
var websites []website
// A function to create a developer
func hireDeveloper(wg *sync.WaitGroup, workNumber int,
developerCreatedc chan developer, devs []developer) {
defer wg.Done()
developerNumber := fmt.Sprintf("developer_%d", workNumber)
d := developer{name: developerNumber}
fmt.Println("Hired", d.name)
developerCreatedc <- d
}
// A function to create a website
func createComputer(wg *sync.WaitGroup, developerCreatedc chan developer, websitePerComputer int, websites []website) {
defer wg.Done()
// Assign the developer to the website creation // N number of the website
d := <-developerCreatedc
for i := 0; i <= websitePerComputer; i++ {
fmt.Println("Delegate", d.name, "to set the time to start
building the website")
d.setTimeForWebsite = time.Now()
fmt.Println(d.name, "Finish calculating to build the website", d.setTimeForWebsite)
web := website{owner: d.name, created: d.setTimeForWebsite}
websites = append(websites, web)
fmt.Println(len(websites))
time.Sleep(time.Second * 2)
fmt.Println(d.name, "Created website at", web.created)
}
}
func main() {
// Make a channel for when developer is hired
developerCreatedC := make(chan developer)
// create a sync group
wg := &sync.WaitGroup{}
// Assume that number of websites are 20
numberOfWebsites := 20
// Assume that number of developers are 5
numberOfDevelopers := 5
// Divide the websites to 5 developers
websitePerDeveloper := numberOfWebsites / numberOfDevelopers
// add the sync
wg.Add(1)
for i := 1; i <= numberOfDevelopers; i++ {
go func(producerNumber int) {
hireDeveloper(wg, producerNumber, developerCreatedC,
developers)
}(i)
}
wg.Add(1)
for i := 1; i <= websitePerDeveloper; i++ {
createComputer(wg, developerCreatedC, 5, websites)
}
wg.Wait()
}
The playground https://play.golang.org/p/QSOv5jp3T94
The behaviour is a bit sometimes, one developer created more than 4 websites, even though it is supposed to create only 4
Thanks
wg.Add() should be equal to the number number of go routine you are running. Also createComputer(wg, developerCreatedC, websitePerDeveloper, websites) should be per developer basis.
package main
import (
"fmt"
"sync"
"time"
)
type developer struct {
name string
setTimeForWebsite time.Time
}
type website struct {
owner string
created time.Time
}
var developers []developer
var websites []website
// A function to create a developer
func hireDeveloper(wg *sync.WaitGroup, workNumber int, developerCreatedc chan developer, devs []developer) {
defer wg.Done()
developerNumber := fmt.Sprintf("developer_%d", workNumber)
d := developer{name: developerNumber}
fmt.Println("Hired", d.name)
developerCreatedc <- d
}
// A function to create a website
func createComputer(wg *sync.WaitGroup, developerCreatedc chan developer, websitePerComputer int, websites []website) {
defer wg.Done()
// Assign the developer to the website creation // N number of the website
d := <-developerCreatedc
for i := 0; i <= websitePerComputer; i++ {
fmt.Println("Delegate", d.name, "to set the time to start building the website")
d.setTimeForWebsite = time.Now()
web := website{owner: d.name, created: d.setTimeForWebsite}
websites = append(websites, web)
fmt.Println(len(websites))
time.Sleep(time.Second * 2)
fmt.Println(d.name, "Created website at", web.created)
}
}
func main() {
// Make a channel for when developer is hired
developerCreatedC := make(chan developer)
// create a sync group
wg := &sync.WaitGroup{}
// Assume that number of websites are 20
numberOfWebsites := 20
// Assume that number of developers are 5
numberOfDevelopers := 5
// Divide the websites to 5 developers
websitePerDeveloper := numberOfWebsites / numberOfDevelopers
for i := 1; i <= numberOfDevelopers; i++ {
// add the sync
wg.Add(1)
go func(producerNumber int) {
hireDeveloper(wg, producerNumber, developerCreatedC, developers)
}(i)
wg.Add(1)
go createComputer(wg, developerCreatedC, websitePerDeveloper, websites)
}
wg.Wait()
}
You receive the error because you do wg.Add(1) before the loop.
Every call to hireDeveloper() and createComputer() calls wg.Done(), so already in the first for loop wg wants to count down till -4 which is not possible thus the panic.
A possible solution would be:
wg.Add(numberOfDevelopers)
for i := 1; i <= numberOfDevelopers; i++ {...}
....
wg.Add(websitePerDeveloper)
for i := 1; i <= websitePerDeveloper; i++ {...}
or you pull wg.Add into the for loop:
for i := 1; i <= numberOfDevelopers; i++ {
wg.Add(1)
go func(producerNumber int) {
hireDeveloper(wg, producerNumber, developerCreatedC,
developers)
}(i)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With