Return after channel ends parent routine - go

I have a code excerpt of a main running a go routine below. Why does this NOT happen: the main exits after it receives the done and before job return, which would make the child process zombie. Any reference to golang docs would be helpful.
func main() {
var jobDone = make(chan bool)
go job(jobDone)
<-jobDone
}
func job(done chan bool) {
for {
select {
case <-someOtherGlobalChannel:
//Please ignore this case/channel
fmt.Println("SOmeOtherChannel received")
default:
if check_somthing_expression {
done <- true
return
}
}
}
}

With these changes, your main will exit after the done channel
package main
import (
"fmt"
)
func main() {
var jobDone = make(chan bool)
go job(jobDone)
<-jobDone
}
func job(done chan bool) {
for {
select {
case <-someOtherGlobalChannel:
//Please ignore this case/channel
fmt.Println("SOmeOtherChannel received")
default:
if check_somthing_expression {
done <- true
return
}
}
}
}

Zombie Process
"...which would make the child process zombie"
go job() does not start a separate process, it starts another goroutine. You have a main goroutine, and a job goroutine in this program. Language spec:
A "go" statement starts the execution of a function call as an independent concurrent thread of control, or goroutine, within the same address space.
Therefore you will not be creating a Unix zombie process.
Main Not Exiting Before Job
"Why does this NOT happen: the main exits after it receives the done and before job return...?"
Reason #1: The Receive Operations are Blocking Both Goroutines
(1) Because there's no send statement on channel done in job.
<-done
is a receive operation. See "Receive operator" in Go spec:
For an operand ch of channel type, the value of the receive operation <-ch is the value received from the channel ch.
See also "Send statements" in Go spec:
ch <- 3 // send value 3 to channel ch
You need a send statement. E.g.:
done <- true
More explanatory text and examples are available in the Go Tour and Effective Go.
...And there's a second reason:
Reason #2: There's Nothing To Do Between Send and Return
(2) Because, even if you change the receive operation to a send statement, there's nothing to do in the job goroutine between when it sends on the channel and it returns, so it's not likely for any time to pass from one to the next. If you want that to happen, add a sleep in job using the time package:
done <- true
time.Sleep(time.Second * 30)
return

you need to put some bool message to your done channel,then the <-jobDone
} can get some message to finish the block

Related

Not quite grasping goroutines and channels, please break this code down

I'm following a quick intro to Go and one of the examples is:
package main
import (
"fmt"
"time"
)
func worker(done chan bool) {
fmt.Print("working...")
time.Sleep(time.Second)
fmt.Println("done")
done <- true
}
func main() {
done := make(chan bool, 1)
go worker(done)
<-done
}
I understand whats occuring but I guess I'm not grasping the sequence of events or the limitations?
A channel is created called done with a buffer size of 1.
The channel is passed into a function
After the timer is complete it adds a true boolean to the channel
I'm not sure what the final <-done is doing though
from: https://gobyexample.com/channel-synchronization
Receiver operator <- followed by channel name (done in this case) is used to wait for a value written to channel from worker goroutine. (i.e this read operation will be blocking. If you omit <-done, main goroutine will exit immediately even before worker's goroutine start and you won't be able to see results)
You can do whatever you want with <-done as value: assign it to another variable, pass it as a parameter to another function or just ignore it as in your case... etc.

Go channel readyness

I am trying to understand channels in Go. I have read that by default sends and receives block until both the sender and receiver are ready. But how do we figure out readyness of sender and receiver.
For example in the following code
package main
import "fmt"
func main() {
ch := make(chan int)
ch <- 1
fmt.Println(<-ch)
}
The program will get stuck on the channel send operation waiting forever for someone to read the value. Even though we have a receive operation in println statement it ends up in a deadlock.
But for the following program
package main
import "fmt"
func main() {
ch := make(chan int)
go func () {
ch <- 1
}()
fmt.Println(<-ch)
}
The integer is passed successfully from go routine to main program. What made this program work? Why second works but first do not? Is go routine causing some difference?
Let's step through the first program:
// My notes here
ch := make(chan int) // make a new int channel
ch <- 1 // block until we can send to that channel
// keep blocking
// keep blocking
// still waiting for a receiver
// no reason to stop blocking yet...
// this line is never reached, because it blocks above forever.
fmt.Println(<-ch)
The second program splits the send off into its own line of execution, so now we have:
ch := make(chan int) // make a new int channel
go func () { // start a new line of execution
ch <- 1 // block this second execution thread until we can send to that channel
}()
fmt.Println(<-ch) // block the main line of execution until we can read from that channel
Since those two lines of execution can work independently, the main line can get down to fmt.Println and try and receive from the channel. The second thread will wait to send until it has.
The go routine absolutely makes a difference. The go routine that writes to the channel will be blocked until your main function is ready to read from the channel in the print statement. Having two concurrent threads, one that reads and one that writes fulfills the readiness on both sides.
In your first example, the single thread gets blocked by the channel write statement and will never reach the channel read.
You need to have a concurrent go routine to read from a channel whenever you write to it. Concurrency goes hand-in-hand with channel usage.

Running a Go routine indefinitely

I have a function that calls another function that returns a chan array. I currently have a for loop looping over the range in the array which runs the program indefinitely outputting the channel updates as the come through.
func getRoutes() {
for r := range rtu {
if r.Type == 24 {
fmt.Printf("Route added: %s via %s\n",r.Dst.String(),r.Gw.String())
} else if r.Type == 25 {
fmt.Printf("Route deleted: %s via %s\n",r.Dst.String(),r.Gw.String())
}
}
}
When I call getRoutes() from main() everything works as planned though, it's blocking the application. I've tried calling go getRoutes() from main() though it appears as if the function isn't being called at all.
How can I run this function in the background in a non-blocking way using go routines?
When the primary goroutine at main exits, all goroutines you might have spawned will be orphaned and eventually die.
You could keep the main goroutine running forever with an infinite loop with for {}, but you might want to keep an exit channel instead:
exit := make(chan string)
// Spawn all you worker goroutines, and send a message to exit when you're done.
for {
select {
case <-exit:
os.Exit(0)
}
}
Update: Cerise Limón pointed out that goroutines are just killed immediately when main exits. I think this is supposed to be the officially specified behaviour.
Another update: The for-select works better when you have multiple ways to exit / multiple exit channels. For a single exit channel you could just do
<-exit
at the end instead of a for and select loop.
Although other people have answered this, I think their solutions can be simplified in some cases.
Take this code snippet:
func main() {
go doSomething()
fmt.Println("Done.")
}
func doSomething() {
for i := 0; i < 10; i++ {
fmt.Println("Doing something...")
time.Sleep(time.Second)
}
}
When main() begins executing, it spawns a thread to concurrently execute doSomething(). It then immediately executes fmt.Println("Done."), and the main() finishes.
When main() finishes, all other goroutines will be orphaned, and die.
To avoid this, we can put a blocking operation at the end of main() that waits for input from a goroutine. It's easiest to do this with a channel:
var exit = make(chan bool)
func main() {
go doSomething()
<-exit // This blocks until the exit channel receives some input
fmt.Println("Done.")
}
func doSomething() {
for i := 0; i < 10; i++ {
fmt.Println("Doing something...")
time.Sleep(time.Second)
}
exit<-true // Notify main() that this goroutine has finished
}
Your main() returns before getRoutes()-goroutine finishes. When main() returns, the program exits, thereby killing all the running goroutines. (It's also totally possible that main() returns even before the goroutine gets a chance to get scheduled by go runtime.)
If you want main() (or any other function) to wait for a group of goroutines to finish, you'd have to make the function explicitly wait somehow. There're multiple ways to do that. sync.WaitGroup.Wait() can be used to wait for a group of the goroutines to finish. You could also use channels to communicate when goroutines are done.

Go: Act on Signal while not Blocking Operations

I want to fire the ps command continuously in a goroutine to monitor mem and cpu usages. I didn't use top because top doesn't allow me to select columns as ps does. This goroutine needs to receive a stop signal to stop the command, but I don't know how not to block running the command while waiting the signal. For top I can do:
top := exec.Command("top")
<-stop // blocking
top.Process.Signal(os.Kill)
But for ps if I do:
ps := exec.Command("ps")
for {
ps.Run()
<-stop
}
The above code will block on stop. I want to keep firing ps.Run(), while being able to stop when a stop signal is ready. Thanks.
One way that you could achieve this is by utilizing the for/select timeout idiom, there are a couple of similar methods of doing this. Take this trivial example:
package main
import (
"fmt"
"time"
)
func main() {
abort := make(chan struct{})
go func() {
for {
select {
case <-abort:
return
case <-time.After(1 * time.Second):
// replace fmt.Println() with the command you wish to run
fmt.Println("tick")
}
}
}()
// replace time.Sleep() with code waiting for 'abort' command input
time.Sleep(10 * time.Second)
abort <- struct{}{}
}
To modify this example to work in your circumstance place the code that you want to run in the <-time.After(): case, which (in this instance) will run once per second, if no other case is available to receive for that duration. And instead of time.Sleep() which I placed at the end, put the code that will interrupt the <-time.After(): case, sending <- struct{}{} on the abort channel (or whatever you name it).
NOTE: In an earlier version of this answer I had abort as a chan bool, as I like the clarity of <-abort true and don't consider chan struct{} to be as clear, I opted to change it in this example however, as <- struct{}{} isn't unclear, especially once you've gotten used to the pattern.
Also, if you want the command to execute on each iteration of the for loop and not wait for a timeout then you can make that case default:, remove <-time.After() and it will run on each iteration of the loop where another channel is not ready to receive.
You can play with this example in the playground if you'd like, although it will not allow syscalls, or the default: case example to be run in that environment.
To run it over and over, without sleep:
func run(stop <-chan struct{}) {
ps := exec.Command("ps")
for {
select {
case <-stop:
return
default:
ps.Run()
//processing the output
}
}
}
And then go run(stop). And to run it every 3 seconds (for example):
func run(stop <-chan struct{}) {
ps := exec.Command("ps")
tk := time.Tick(time.Second * 3)
for {
select {
case <-stop:
return
case <-tk:
ps.Run()
//processing the output
}
}
}

Can't get concurrency to work as I expect it

I am trying to understand why my code does not work, so I managed to recreate the problem in a simpler example.
I expected this code to output the string "broadcasted", but it does not output anything.
package main
import (
"fmt"
"time"
)
type hub struct {
handle chan []byte
broadcast chan []byte
}
func (h *hub) init() {
for {
select {
case m := <-h.handle:
handler(m)
case _ = <-h.broadcast:
fmt.Println("broadcasted")
}
}
}
var socketHub = hub{
handle: make(chan []byte),
broadcast: make(chan []byte),
}
func main() {
go socketHub.init()
m := []byte("this is the message")
socketHub.handle <- m
time.Sleep(time.Second * 2)
}
func handler(m []byte) {
// Do some stuff.
socketHub.broadcast <- m
}
Why does this not work?
Your broadcast channel is unbuffered. This means that:
You send the message to the handle channel: main goroutine blocks until...
In the goroutine, the select case gets the message...
And calls (in the goroutine) handler, which sends the message to the broadcast channel, blocking until...
And that's it: your child goroutine is blocking, waiting on itself to pick the message. Concurrently, your main goroutine sleeps, then reaches the end of main, exits and terminates the program.
You can 'solve' it in several ways:
Make your broadcast channel buffered: this way, goroutine sends the message, which succeeds immediately, and returns in the for loop, selecting it back and printing as intended
Make your send a (new) goroutine, either in handler, or by calling go handler(m) in your loop
Have two different goroutines listen to handler and broadcast
Which one you choose depends on the exact problem you try to solve: in this tiny example, it's hard to find a 'best' one.

Resources