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.