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