I'm aware of the sync
package and its waitgroup
options, I don't want to use it for this test. I'm testing a kind of semaphore.
So I've got:
package main
import (
"fmt"
"os"
"time"
)
func main() {
fmt.Print("wassap")
jobs := make(chan int)
processStarted := make(chan struct{}, 1)
processCompleted := make(chan struct{}, 1)
createJobs(jobs)
go func() {
worker(jobs, processStarted, processCompleted)
}()
go func() {
sync(processStarted, processCompleted)
}()
time.Sleep(3600 * time.Second)
fmt.Print("\nend of main...")
interrupt := make(chan os.Signal)
<-interrupt
}
func createJobs(jobs chan<- int) {
defer close(jobs)
for i := 1; i < 20; i++ {
jobs <- i
}
}
func worker(jobs <-chan int, processStarted <-chan struct{}, processCompleted <-chan struct{}) {
for {
select {
case i := <-jobs:
fmt.Printf("\nFetching job #%d from channel", i)
time.Sleep(2 * time.Second)
case <-processStarted:
fmt.Print("\nProcess Started. Waiting for it to be completed")
<-processCompleted
fmt.Print("\nProcess completed")
}
}
}
func sync(processStarted chan<- struct{}, processCompleted chan<- struct{}) {
// acquire semaphore. Send signal to channel to indicate that it is busy
processStarted <- struct{}{}
for i := 1; i < 5; i++ {
fmt.Printf("\nprocessing %d", i)
time.Sleep(5 * time.Second)
}
// release semaphore
processCompleted <- struct{}{}
}
What I'm trying to test is fairly simple: I've got a createJobs
function whose only purpose is to add elements to a channel, in this case an int channel. Then I've got a worker
that is going to pull out objects from that channel and sleep for 2 seconds before pulling the next element.
Now, there's also a sync function. The sole purpose of this function is to simulate a process that was initiated while worker
was running. If this process is active, then processing of jobs
elements should be stopped while sync
ends, reason why I've got two channels, one to indicate that the process started and one that the process ended.
When running my code I'm getting the following error:
fatal error: all goroutines are asleep - deadlock!
If I modify the way createJobs
is called by wrapping it out in a goroutine like this:
go func() {
createJobs(jobs)
}()
then my code runs correctly.
I just want to understand why this is happening. I mean: main
routine is being executed, then it hits the call to createJobs
(no wrap) so main
routine is supposed to be blocked until this call ends. Once createJobs
has ended, it means there are elements in the channel. main
continues execution and spin up the other goroutines worker
and sync
to do their stuff. Before main
ends, I'm simply adding a sleeper to give time to the previously created goroutines to finish.
I'm not asking to other solutions to this problem, I just want to know what's going on when createJobs
occurs outside a goroutine.