package main
import (
"fmt"
)
type A struct{
exit chan bool
}
func (a *A) f(){
select{
//the routine process
//quit
case <- a.exit:
fmt.Println("-----over-----")
a.exit <- true
fmt.Println("+++++over++++++")
}
}
func main() {
a := A{}
go a.f()
a.exit = make(chan bool)
a.exit <- true
}
I'd like to run muti goroutines,and I want let the main func to notice other goroutine to quit.
here is my code,but the program block in the select,the program only output "-----over-----",without "+++++over++++++",what's wrong with the code?Grateful for your help.
Your program blocks because that is what you have written, consider this order of operations:
main goroutine starts a.f goroutine.
a.f blocks trying to read from the nil channel a.exit.
main sets a.exit to be an unbuffered channel, a.f is now blocked reading from the new channel, this is allowed.
main writes a value into a.exit and a.f reads the value from a.exit, this synchronises the goroutines, nether are blocked now.
a.f now blocks trying to write into the unbuffered a.exit, this will never unblock because nobody will ever try to read from the channel again.
main now exits and causes all other goroutines to exit, this might happen before step 5.
So the reasons your program never outputs +++++over++++++ are:
Your a.f goroutine blocks at a.exit <- true because no other goroutine will read this value from the channel.
Your main goroutine will probably exit and terminate the entire program before a.f can finish working.
I think you are asking how to make main exit after the goroutine is finished, this is the most simple example of that:
package main
import (
"fmt"
)
type A struct {
exit chan struct{}
}
func (a *A) f() {
defer close(a.exit) // Close the chanel after f() finishes, closed channels yield the zero-value so <-a.exit will unblock
fmt.Println("+++++over++++++")
}
func main() {
a := A{}
go a.f()
a.exit = make(chan struct{})
<-a.exit
}
Related
I read it on (https://www.geeksforgeeks.org/channel-in-golang/) that:
"In the channel, the send and receive operation block until another side is not ready by default.
It allows goroutine to synchronize with each other without explicit locks or condition variables."
To test above statement, I have written a sample program mentioned below:
Program:
package main
import (
"fmt"
"sync"
"time"
)
func myFunc(ch chan int) {
fmt.Println("Inside goroutine:: myFunc()")
fmt.Println(10 + <-ch) //<-- According to rule, control will be blocked here until 'ch' sends some data so that it will be received in our myFunc() go routine.
}
func main() {
fmt.Println("Start Main method")
// Creating a channel
ch := make(chan int)
go myFunc(ch) //<-- This go routine started in a new thread
time.Sleep(2 * time.Second) //<--- introduced a Sleep of 2 seconds to ensure that myFunc() go routine executes before main thread
ch <- 10
fmt.Println("End Main method")
}
I was expecting below output:
Start Main method
Inside goroutine:: myFunc()
20
End Main method
But, Actual output received is:
Start Main method
Inside goroutine:: myFunc()
End Main method
Why the value sent through channel is not printed?
I think, it is because main thread finished its execution first and hence, all other goroutine also terminated.
If that is the case, then, why does the rule said - It allows goroutine to synchronize with each other without explicit locks or condition variables.
Because, to get the expected output, I have to use sync.WaitGroup to tell the main thread to wait for the other goroutine to finish. Isn't it violating the above rule as I am using locks in form of waitgroup?
PS: I am learning golang. So please forgive if I get the concept totally wrong.
The main goroutine exists before the myFunc goroutine is able to print the output. Here is an implementation which ensures that myFunc goroutine finishes before the main goroutine exits.
package main
import (
"fmt"
"sync"
"time"
)
func myFunc(ch chan int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println("Inside goroutine:: myFunc()")
fmt.Println(10 + <-ch) //<-- According to rule, control will be blocked here until 'ch' sends some data so that it will be received in our myFunc() go routine.
}
func main() {
fmt.Println("Start Main method")
// Creating a channel
ch := make(chan int)
wg := sync.WaitGroup{}
wg.Add(1)
go myFunc(ch, &wg) //<-- This go routine started in a new thread
time.Sleep(2 * time.Second) //<--- introduced a Sleep of 2 seconds to ensure that myFunc() go routine executes before main thread
ch <- 10
wg.Wait()
fmt.Println("End Main method")
}
The channels are used here for synchronization and it works as described in documentation. It does not mean that the code starting from this point in the code will be executed at the same speed. It only means that main goroutine will not continue if myFunc goroutine is not reading from channel. And myFunc will wait for main goroutine to push data to channel. After this happen both goroutines will continue it execution independently.
Try this, used your code as basis
package main
import (
"fmt"
"time"
)
func myFunc(ch chan int, done chan struct{}) {
defer close(done) // channel will be closed in the function exit phase
fmt.Println("Inside goroutine:: myFunc()")
fmt.Println(10 + <-ch) //<-- According to rule, control will be blocked here until 'ch' sends some data so that it will be received in our myFunc() go routine.
}
func main() {
fmt.Println("Start Main method")
// Creating a channel
ch := make(chan int)
done := make(chan struct{}) // signal channel
go myFunc(ch, done) //<-- This go routine started in a new thread
time.Sleep(2 * time.Second) //<--- introduced a Sleep of 2 seconds to ensure that myFunc() go routine executes before main thread
ch <- 10
<-done // waiting for function complete
fmt.Println("End Main method")
}
Or use Jaroslaw's suggestion.
Because go is so fast... https://play.golang.org/p/LNyDAA3mGYY
After you send to channel scheduler isn't fast enoght... and program exists. I have introduced an additional context switcher for scheduler to show effect.
Yes, you are right
I think, it is because main thread finished its execution first and hence, all other goroutine also terminated.
If you check the above program execution. The sleep is before main thread writes to the channel. Now even though which goroutine() will have CPU time is completely arbitary, but in the above case if the main sleeps before the explicit sleep logic. myFunc will be blocked as there is no data in ch
Here I made a slight change to the above code to make main sleep after writing data into Channel. It gives the expected output, Without using waitgroup or quit channels.
package main
import (
"fmt"
"time"
)
func myFunc(ch chan int) {
fmt.Println("Inside goroutine:: myFunc()")
fmt.Println(10 + <-ch) //<-- According to rule, control will be blocked here until 'ch' sends some data so that it will be received in our myFunc() go routine.
}
func main() {
fmt.Println("Start Main method")
// Creating a channel
ch := make(chan int)
go myFunc(ch) //<-- This go routine started in a new thread
ch <- 10
time.Sleep(2 * time.Second) //<--- introduced a Sleep of 2 seconds to ensure that myFunc() go routine executes before main thread
fmt.Println("End Main method")
}
It is currently a race condition between the myFunc being able to print and your main function exiting.
If we look at the spec for program execution at
https://golang.org/ref/spec#Program_execution
Program execution begins by initializing the main package and then invoking the function main. When that function invocation returns, the program exits. It does not wait for other (non-main) goroutines to complete.
It is still your job to make sure that all spawned goroutines will complete before your main goroutine exists.
In your case, you could use a waitgroup as you mentioned or you could use a done channel.
https://play.golang.org/p/RVr0HXuUMgn
Given your code you could also close the channel you use to send the integer over since you are passing it to the function as bidirectional but it's not strictly idiomatic.
https://play.golang.org/p/wGvexC5ZgIi
golang: Why there's no deadlock in this code?
Please go through this following code:
package main
import (
"fmt"
"time"
)
func f1(done chan bool) {
done <- true
fmt.Printf("this's f1() goroutine\n")
}
func f2(done chan bool) {
val := <-done
fmt.Printf("this's f2() goroutine. val: %t\n", val)
}
func main() {
done1 := make(chan bool)
done2 := make(chan bool)
go f1(done1)
go f2(done2)
fmt.Printf("main() go-routine is waiting to see deadlock.\n")
time.Sleep(5 * time.Second)
}
As one can see, go-routine f1() is sending a value onto the channel. And go-routine f2() is receiving a value from a channel.
However, there's no go-routine receiving from the channel which is being sent onto by go-routine f1().
Similarly, there's no go-routine sending onto the channel which is being received from by go-routine f2().
As #icza's comment correctly states, a deadlock happens when all goroutines are stuck and can't make progress. In your case f1 and f2 are stuck, but the main goroutine is not - so this isn't a deadlock.
However, it is a goroutine leak! Goroutine leaks happen when some code finishes its logical existence but leaves goroutines running (unterminated). I've found tools like github.com/fortytw2/leaktest useful for detecting goroutine leaks, and it would detect the issue in your code - give it a try.
Here's a modified code sample:
import (
"testing"
"time"
"github.com/fortytw2/leaktest"
)
func f1(done chan bool) {
done <- true
fmt.Printf("this's f1() goroutine\n")
}
func f2(done chan bool) {
val := <-done
fmt.Printf("this's f2() goroutine. val: %t\n", val)
}
func TestTwoGoroutines(t *testing.T) {
defer leaktest.CheckTimeout(t, time.Second)()
done1 := make(chan bool)
done2 := make(chan bool)
go f1(done1)
go f2(done2)
}
When you run this test, you'll see something like:
--- FAIL: TestTwoGoroutines (1.03s)
leaktest.go:132: leaktest: timed out checking goroutines
leaktest.go:150: leaktest: leaked goroutine: goroutine 7 [chan send]:
leaktest-samples.f1(0xc000016420)
leaktest-samples/leaktest1_test.go:45 +0x37
created by leaktest-samples.TestTwoGoroutines
leaktest-samples/leaktest1_test.go:60 +0xd1
leaktest.go:150: leaktest: leaked goroutine: goroutine 8 [chan receive]:
leaktest-samples.f2(0xc000016480)
leaktest-samples/leaktest1_test.go:50 +0x3e
created by leaktest-samples.TestTwoGoroutines
leaktest-samples/leaktest1_test.go:61 +0xf3
As #icza said, the main goroutine can continue and ultimately terminate.
If you remove the go keyword from either of the two function calls (make them occur on the main goroutine) then the application has a deadlock. See this go playground (it highlights the deadlock for you) https://play.golang.org/p/r9qo2sc9LQA
There's one more thing to it.
func f1(done chan bool) {
fmt.Printf("f1()\n")
}
func main() {
done := make(chan bool)
go f1(done)
done <- true
}
Here, the caller go-routine clearly gets stuck since there's no go-routine in existence that's receiving from the channel.
Here, not that all the go-routines are blocked (f1() slips through), but there's still a dead-lock. The reason being, there has to be at least 1 go routine that should be receiving from the channel.
But this clearly contradicts the above comment and not all go-routines are blocked here.
I'm reading this blog, https://medium.com/golangspec/goroutine-leak-400063aef468, and have adapted the following example illustrating a goroutine leak due to receiving from a nil channel:
package main
import (
"flag"
"fmt"
"runtime"
"time"
)
var initChannel bool
func main() {
flag.Parse()
var ch chan int
if initChannel {
ch = make(chan int, 1)
ch <- 1
}
go func(ch chan int) {
<-ch
}(ch)
c := time.Tick(1 * time.Second)
for range c {
fmt.Printf("#goroutines: %d\n", runtime.NumGoroutine())
}
}
func init() {
flag.BoolVar(&initChannel, "init", false, "initialize channel")
}
I've noticed that if I run it with initChannel false, the number of goroutines is 2:
> go run main.go
#goroutines: 2
#goroutines: 2
whereas if I run it with true, the number is 1:
> go run main.go --init
#goroutines: 1
#goroutines: 1
I don't quite understand why this is the case, however. I only see one go statement, so I would expect only one goroutine in either case. Why are there two goroutines when reading from a nil channel?
When your app starts, there is already one goroutine that runs the main() function.
If you don't initialize the ch channel, it will remain its zero value which is nil for channels. Spec: Receive operator:
Receiving from a nil channel blocks forever.
For details, see How does a non initialized channel behave?
So if the channel is nil, the launched goroutine will never end. So you will have 2 goroutines: the main goroutine and the one you launched.
If you initialize the channel with 1 buffer and send one value on it, then you will also have 2 goroutines for a "short period of time", but the launched goroutine can receive a value from it and then end immediately. So there will be a single goroutine remaining, the main goroutine.
The following code logged an error:
fatal error: all goroutines are asleep - deadlock!
package main
import "fmt"
func main() {
ch := make(chan int)
ch <- 1
fmt.Println(<-ch)
}
But when I changed the code into this:
package main
import "fmt"
func assign (ch chan int) {
ch <- 1
}
func main() {
ch := make(chan int)
go assign (ch)
fmt.Println(<-ch)
}
"1" was printed out.
Then I used buffered channels:
package main
import "fmt"
func main() {
ch := make(chan int, 2)
ch <- 1
ch <- 2
fmt.Println(<-ch)
fmt.Println(<-ch)
}
"1" and "2" can also be printed out.
I'm a little confused about the situation. Thanks in advance!
Why the deadlock happened:
In the first code snippet you have only one main goroutine and it is blocked when you are trying to write into the channel here:
ch <- 1
Because nobody reads from the channel and the main goroutine is waiting for this to continue.
See Effective Go -> Channels
If the channel is unbuffered, the sender blocks until the receiver has received the value.
The sender is main function, the receiver is also main function.
How to avoid the deadlock:
In order to solve this, you have two options:
Option 1: make the ch channel buffered like this:
ch := make(chan int, 1) // buffer length is set to 1
From A Tour of Go
Sends to a buffered channel block only when the buffer is full.
So, you can write to the channel until the buffer is full. Then somebody has to start reading from the channel.
Option 2: write to the channel from a goroutine, like you did in the second code snippet:
func assign(ch chan int) {
ch <- 1
}
func main() {
ch := make(chan int)
go assign(ch) // does not block the main goroutine
fmt.Println(<-ch) // waiting to read from the channel
}
In this case main function will be executed until fmt.Println(<-ch) and continues as soon as it can read from the channel.
When you are using unbuffered channel, goroutine is blocked during write until someone does the read.
In your first snippet, there is an unbuffered channel and single goroutine (main goroutine).
So when you are trying to write:
ch <- 1
Nobody reads from the channel yet. The main goroutine is blocked and this line is never executed:
fmt.Println(<-ch)
That's why you've got the deadlock error.
In the second example, you still using unbuffered channel, which means write operation blocks the goroutine.
But by using go you are running the second goroutine.
It means even if this new goroutine will be blocked during write (in your assign function), the main goroutine will continue to work and fmt.Println(<-ch) will be executed and do the read (which in turn unblock background goroutine and assign function will finally reach the end).
To get more understanding about channels and goroutines, this snippet will give the same result (as your second snippet):
package main
import "fmt"
func print(ch chan int) {
fmt.Println(<-ch)
}
func main() {
ch := make(chan int)
go print(ch)
ch <- 1
}
When you are working with a buffered channel (third snippet), you can do N write operations without blocking goroutine (where N is the size of the buffer).
That's why in your example you did 2 writes without blocking and is able to read them later. But if your buffer is less than the count of write operations, and nobody do the read, you will fall into the same blocking issues (see the explanation of 1&2 snippets).
I'm new to Go and am stumped on what appears to be a somewhat-rare race condition with a very small block of code running on Linux with Go version 1.2.
Basically, I create a channel for an int, start a go routine to read from the channel, and then write a single int to the channel.
package main
import "fmt"
func main() {
channel := make(chan int)
go func() {
number := <- channel
fmt.Printf("GOT IT: %d\n", number)
}()
fmt.Println("[+] putting num on channel")
channel <- 42
fmt.Println("[-] putting num on channel")
}
The output about 90% of the time is as expected:
$ go run test.go
[+] putting num on channel
GOT IT: 42
[-] putting num on channel
However, about 10% of the time, the go routine simply does not read the number from the channel and prints nothing:
$ go run test.go
[+] putting num on channel
[-] putting num on channel
I'm puzzled because this code is very similar to the example at https://gobyexample.com/channels, (which I do not have this problem with) except that I'm reading from the channel in my go routine instead of writing to the channel.
Do I have a fundamental misunderstanding of how channels work or is there something else at play here?
You should wait until your goroutine executes, and then your, for example, you can do it with sync.WaitGroup:
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
channel := make(chan int)
wg.Add(1)
go func() {
number := <-channel
fmt.Printf("GOT IT: %d\n", number)
wg.Done()
}()
fmt.Println("[+] putting num on channel")
channel <- 42
wg.Wait()
fmt.Println("[-] putting num on channel")
}
(goplay: http://play.golang.org/p/VycxTw_4vu)
Also you can do it with a "notification channel", that indicates that job is done:
package main
import "fmt"
func main() {
channel := make(chan int)
done := make(chan bool)
go func() {
number := <-channel
fmt.Printf("GOT IT: %d\n", number)
done <- true
}()
fmt.Println("[+] putting num on channel")
channel <- 42
<-done
fmt.Println("[-] putting num on channel")
}
(goplay: http://play.golang.org/p/fApWQgtr4D)
You seem to be expecting the receiving goroutine to run to completion before the second fmt.Println executes. This is not guaranteed to be the case. If the program terminates, goroutines are not guaranteed to reach the end of their functions.
When you see the output that doesn't display the "GOT IT" message, the channel delivered its message, but the main function completed before the goroutine did. The program terminated, and the goroutine never gets the chance to call fmt.Printf
In the example you cited, the main function ends with this:
go func() { messages <- "ping" }()
msg := <-messages
fmt.Println(msg)
Since the main function blocks until it receives a message, the goroutine always runs to completion in this example. In your code, your goroutine executes a step after it receives from the channel, and it's undefined whether the goroutine or the main function will execute the next line after the receive.
You have two goroutines, one in main() (which is implicitly a goroutine), and the anonymous one.
They communicate over a synchronous channel, so after the channel communication, it's guaranteed that they're synchronised.
At this point, the code left in the main() goroutine looks like this:
fmt.Println("[-] putting num on a channel")
and the code left in the anonymous goroutine looks like this:
fmt.Println("GOT IT: %d\n", number)
Now you're racing: the output from these Printlns may appear in either order, or even intermingled. When the Println() from main finishes, the next thing that will happen on that goroutine is that your program will be stopped. This may prevent some or all of the Println from the anonymous goroutine from appearing.