Signal goroutines to stop with channel close
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?
go channel
|
show 7 more comments
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?
go channel
2
When you closea.QuitChan
, that will terminatea
's goroutine (sooner or later), but the goroutine in theb
package has no termination condition, that will run forever. Also, the app will not terminate just because some "random" goroutine ended, the app terminates when themain
goroutine ends (we don't know what yourmain
goroutine is).
– icza
Nov 12 '18 at 21:59
1
Can you elaborate on what you mean by "they keep running"?
– poy
Nov 12 '18 at 22:10
1
You have a loop inb
's goroutine, and there is no return nor break statement in it, so it will run forever. A goroutine or its loop will not magically end or return just because an independent goroutine ended.
– icza
Nov 12 '18 at 22:17
2
Just because you see"Stop called, closing channel"
printed, that is not guarantee that theQuitChan
is closed (as the print is before theclose()
call). Put a print statement after theclose()
and confirm if you see that printed.
– icza
Nov 12 '18 at 22:31
1
You are copying the WaitGroup. Use a pointer instead.go vet
should complain about that, I think.
– Peter
Nov 13 '18 at 0:24
|
show 7 more comments
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?
go channel
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?
go channel
go channel
edited Nov 13 '18 at 7:42
Chen A.
asked Nov 12 '18 at 21:43
Chen A.Chen A.
5,19221531
5,19221531
2
When you closea.QuitChan
, that will terminatea
's goroutine (sooner or later), but the goroutine in theb
package has no termination condition, that will run forever. Also, the app will not terminate just because some "random" goroutine ended, the app terminates when themain
goroutine ends (we don't know what yourmain
goroutine is).
– icza
Nov 12 '18 at 21:59
1
Can you elaborate on what you mean by "they keep running"?
– poy
Nov 12 '18 at 22:10
1
You have a loop inb
's goroutine, and there is no return nor break statement in it, so it will run forever. A goroutine or its loop will not magically end or return just because an independent goroutine ended.
– icza
Nov 12 '18 at 22:17
2
Just because you see"Stop called, closing channel"
printed, that is not guarantee that theQuitChan
is closed (as the print is before theclose()
call). Put a print statement after theclose()
and confirm if you see that printed.
– icza
Nov 12 '18 at 22:31
1
You are copying the WaitGroup. Use a pointer instead.go vet
should complain about that, I think.
– Peter
Nov 13 '18 at 0:24
|
show 7 more comments
2
When you closea.QuitChan
, that will terminatea
's goroutine (sooner or later), but the goroutine in theb
package has no termination condition, that will run forever. Also, the app will not terminate just because some "random" goroutine ended, the app terminates when themain
goroutine ends (we don't know what yourmain
goroutine is).
– icza
Nov 12 '18 at 21:59
1
Can you elaborate on what you mean by "they keep running"?
– poy
Nov 12 '18 at 22:10
1
You have a loop inb
's goroutine, and there is no return nor break statement in it, so it will run forever. A goroutine or its loop will not magically end or return just because an independent goroutine ended.
– icza
Nov 12 '18 at 22:17
2
Just because you see"Stop called, closing channel"
printed, that is not guarantee that theQuitChan
is closed (as the print is before theclose()
call). Put a print statement after theclose()
and confirm if you see that printed.
– icza
Nov 12 '18 at 22:31
1
You are copying the WaitGroup. Use a pointer instead.go vet
should complain about that, I think.
– Peter
Nov 13 '18 at 0:24
2
2
When you close
a.QuitChan
, that will terminate a
's goroutine (sooner or later), but the goroutine in the b
package has no termination condition, that will run forever. Also, the app will not terminate just because some "random" goroutine ended, the app terminates when the main
goroutine ends (we don't know what your main
goroutine is).– icza
Nov 12 '18 at 21:59
When you close
a.QuitChan
, that will terminate a
's goroutine (sooner or later), but the goroutine in the b
package has no termination condition, that will run forever. Also, the app will not terminate just because some "random" goroutine ended, the app terminates when the main
goroutine ends (we don't know what your main
goroutine is).– icza
Nov 12 '18 at 21:59
1
1
Can you elaborate on what you mean by "they keep running"?
– poy
Nov 12 '18 at 22:10
Can you elaborate on what you mean by "they keep running"?
– poy
Nov 12 '18 at 22:10
1
1
You have a loop in
b
's goroutine, and there is no return nor break statement in it, so it will run forever. A goroutine or its loop will not magically end or return just because an independent goroutine ended.– icza
Nov 12 '18 at 22:17
You have a loop in
b
's goroutine, and there is no return nor break statement in it, so it will run forever. A goroutine or its loop will not magically end or return just because an independent goroutine ended.– icza
Nov 12 '18 at 22:17
2
2
Just because you see
"Stop called, closing channel"
printed, that is not guarantee that the QuitChan
is closed (as the print is before the close()
call). Put a print statement after the close()
and confirm if you see that printed.– icza
Nov 12 '18 at 22:31
Just because you see
"Stop called, closing channel"
printed, that is not guarantee that the QuitChan
is closed (as the print is before the close()
call). Put a print statement after the close()
and confirm if you see that printed.– icza
Nov 12 '18 at 22:31
1
1
You are copying the WaitGroup. Use a pointer instead.
go vet
should complain about that, I think.– Peter
Nov 13 '18 at 0:24
You are copying the WaitGroup. Use a pointer instead.
go vet
should complain about that, I think.– Peter
Nov 13 '18 at 0:24
|
show 7 more comments
1 Answer
1
active
oldest
votes
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 %dn", 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.
I'm already using &wg so that wasn't the issue, but I did made some progress after moving the channel initialization into a function. I declare QuitChan in global scope, init it in Start(), but when I close it now I getpanic: close of nil channel
– Chen A.
Nov 13 '18 at 7:44
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53270533%2fsignal-goroutines-to-stop-with-channel-close%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
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 %dn", 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.
I'm already using &wg so that wasn't the issue, but I did made some progress after moving the channel initialization into a function. I declare QuitChan in global scope, init it in Start(), but when I close it now I getpanic: close of nil channel
– Chen A.
Nov 13 '18 at 7:44
add a comment |
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 %dn", 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.
I'm already using &wg so that wasn't the issue, but I did made some progress after moving the channel initialization into a function. I declare QuitChan in global scope, init it in Start(), but when I close it now I getpanic: close of nil channel
– Chen A.
Nov 13 '18 at 7:44
add a comment |
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 %dn", 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.
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 %dn", 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.
answered Nov 13 '18 at 5:12
James ShiJames Shi
60369
60369
I'm already using &wg so that wasn't the issue, but I did made some progress after moving the channel initialization into a function. I declare QuitChan in global scope, init it in Start(), but when I close it now I getpanic: close of nil channel
– Chen A.
Nov 13 '18 at 7:44
add a comment |
I'm already using &wg so that wasn't the issue, but I did made some progress after moving the channel initialization into a function. I declare QuitChan in global scope, init it in Start(), but when I close it now I getpanic: close of nil channel
– Chen A.
Nov 13 '18 at 7:44
I'm already using &wg so that wasn't the issue, but I did made some progress after moving the channel initialization into a function. I declare QuitChan in global scope, init it in Start(), but when I close it now I get
panic: close of nil channel
– Chen A.
Nov 13 '18 at 7:44
I'm already using &wg so that wasn't the issue, but I did made some progress after moving the channel initialization into a function. I declare QuitChan in global scope, init it in Start(), but when I close it now I get
panic: close of nil channel
– Chen A.
Nov 13 '18 at 7:44
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53270533%2fsignal-goroutines-to-stop-with-channel-close%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
When you close
a.QuitChan
, that will terminatea
's goroutine (sooner or later), but the goroutine in theb
package has no termination condition, that will run forever. Also, the app will not terminate just because some "random" goroutine ended, the app terminates when themain
goroutine ends (we don't know what yourmain
goroutine is).– icza
Nov 12 '18 at 21:59
1
Can you elaborate on what you mean by "they keep running"?
– poy
Nov 12 '18 at 22:10
1
You have a loop in
b
's goroutine, and there is no return nor break statement in it, so it will run forever. A goroutine or its loop will not magically end or return just because an independent goroutine ended.– icza
Nov 12 '18 at 22:17
2
Just because you see
"Stop called, closing channel"
printed, that is not guarantee that theQuitChan
is closed (as the print is before theclose()
call). Put a print statement after theclose()
and confirm if you see that printed.– icza
Nov 12 '18 at 22:31
1
You are copying the WaitGroup. Use a pointer instead.
go vet
should complain about that, I think.– Peter
Nov 13 '18 at 0:24