Signal goroutines to stop with channel close










1














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?










share|improve this question



















  • 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







  • 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 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




    You are copying the WaitGroup. Use a pointer instead. go vet should complain about that, I think.
    – Peter
    Nov 13 '18 at 0:24















1














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?










share|improve this question



















  • 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







  • 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 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




    You are copying the WaitGroup. Use a pointer instead. go vet should complain about that, I think.
    – Peter
    Nov 13 '18 at 0:24













1












1








1


1





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?










share|improve this question















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 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




    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 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




    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




    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




    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 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




    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












1 Answer
1






active

oldest

votes


















2














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.






share|improve this answer




















  • 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










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
);



);













draft saved

draft discarded


















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









2














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.






share|improve this answer




















  • 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















2














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.






share|improve this answer




















  • 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













2












2








2






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.






share|improve this answer












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.







share|improve this answer












share|improve this answer



share|improve this answer










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 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















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

















draft saved

draft discarded
















































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.




draft saved


draft discarded














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





















































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







這個網誌中的熱門文章

Barbados

How to read a connectionString WITH PROVIDER in .NET Core?

Node.js Script on GitHub Pages or Amazon S3