I have got multiple goroutines that select
from two channels: one chan provides data, one chan for signals (kind of done/quit channel).
I use the signals channel to capture signals (kill) and gracefully close the goroutines.
I'm running the 'worker' goroutines from package a
, while the goroutine func that captures signals runs from package b
.
I use the signals package from https://gist.github.com/reiki4040/be3705f307d3cd136e85.
package a
import "sync"
WorkChan := make(chan int)
QuitChan := make(chan struct{})
func Stop() {
fmt.Println("Stop called, closing channel")
close(QuitChan)
}
func Work(wg *sync.WaitGroup) {
var item int
for {
select {
case item = <- WorkChan:
... processing
case <- QuitChan:
wg.Done()
return
}
}
}
The goroutine to catch signals, and call a.Stop()
package b
import (
"os/signal"
"os"
"syscal"
"a"
)
func Signal() {
sChan := make(chan os.Signal, 1)
signal.Notify(signalChan, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-sChan
switch s {
case os.Interrupt, syscall.SIGTERM:
a.Stop()
}
}
}
and this is my main func
package main
import (
"a"
"b"
"sync"
)
func main() {
var wg sync.WaitGroup
go b.Signal()
wg.Add(1) // for simplicity; actual code start multiple goroutines of Work
go a.Work(&wg)
// wait until work is done
wg.Wait()
fmt.Println("Done.")
}
When I kill the running process, I see the printed message from Quit
. I expected that once the channel is closed, the goroutines will select
the QuitChan
case at some point and return.
But they keep running; they continue to process items from WorkChan
. seems like it is ignored. What am I missing here?
Doesn't the channel get closed? How come it is still open?
First I think you should make a simple test, and past it out. It will be more help to let other understand what's your problem.
I changed your code, and make it reading like a go code, instead of other language. Now it's worked.
In your code, there are some mistakes, I marked it as ERROR comment. Some are grammar error, like creating WorkChan
. Some are type error.
One import design thing you should know, when you want exit after execute Stop()
, you should close the WorkChan
where you send data to WorkChan
, insteal of just return at where you receive date.
a.go
package a
import (
"fmt"
"sync"
)
// ERROR: can not do make in global
var WorkChan chan int
var QuitChan chan struct{}
// Create chan when init
func init() {
fmt.Println("Init a")
WorkChan = make(chan int)
QuitChan = make(chan struct{})
}
func Stop() {
fmt.Println("Stop called, closing quit channel")
close(QuitChan)
}
// Close the work channel where you send date
func Start(wg *sync.WaitGroup) {
i := 0
for {
select {
case <-QuitChan:
fmt.Println("Closing work chan")
close(WorkChan)
wg.Done()
return
default:
WorkChan <- i
i++
}
}
}
// Work will exit when workchan closed
func Work(wg *sync.WaitGroup) {
for item := range WorkChan {
fmt.Printf("Receive %d\n", item)
}
wg.Done()
fmt.Println("Work exit")
}
b.go
package b
import (
"github.com/shitaibin/awesome/a"
"os"
"os/signal"
"syscall"
)
func Signal() {
sChan := make(chan os.Signal, 1)
signal.Notify(sChan, syscall.SIGTERM, syscall.SIGINT) // ERROR
for {
s := <-sChan
switch s {
case os.Interrupt, syscall.SIGTERM:
a.Stop()
return // should return free resource
}
}
}
main.go
package main
import (
"fmt"
"github.com/shitaibin/awesome/a"
"github.com/shitaibin/awesome/b"
"sync"
)
func main() {
var wg sync.WaitGroup
go b.Signal()
wg.Add(1) // for simplicity; actual code start multiple goroutines of Work
go a.Work(&wg) // ERROR: pointer
wg.Add(1)
go a.Start(&wg) // Send data and close channel when stop
// wait until work is done
wg.Wait()
fmt.Println("Done.")
}
Result
// omit
Receive 87028
Receive 87029
Receive 87030
Receive 87031
Receive 87032
Receiv^C101 <---- send signal here
Receive 87102
Receive 87103
Receive 87104
Receive 87105
Receive 87106
Receive 87107
Receive 87108
Receive 87109
Receive 87110
Stop called, closing quit channel
Receive 87111
Receive 87112
Closing work chan
Work exit
Done.
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