Anonymous function with goroutines - go

I am trying to understand the difference between calling goroutine with/without anonymous function.
When I try below code with anonymous function it works.
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
go func() {
fmt.Println(<-ch)
}()
go send(1, ch)
time.Sleep(100 * time.Millisecond)
}
Below code without a anonymous function fails with deadlock.
go fmt.Println(<-ch) //fatal error: all goroutines are asleep - deadlock!
The code is available here

The Go Programming Language Specification
Receive operator
For an operand ch of channel type, the value of the receive operation
<-ch is the value received from the channel ch. The channel direction
must permit receive operations, and the type of the receive operation
is the element type of the channel. The expression blocks until a
value is available.
For example,
package main
import "fmt"
func main() {
ch := make(chan int)
go fmt.Println(<-ch)
ch <- 1
}
Playground: https://play.golang.org/p/K3_V92NRWvY
Output:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
// At prog.go: line 7: (<-ch)
fmt.Println(<-ch) evaluates its arguments, a receive on ch. There is no send pending for ch. fmt.Println(<-ch) blocks until a value is available, which never happens, it never gets to ch <- 1.
It is equivalent to:
package main
import "fmt"
func main() {
ch := make(chan int)
arg := <-ch
go fmt.Println(arg)
ch <- 1
}
Playground: https://play.golang.org/p/1wyVTe-8tyB
Output:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
// At prog.go: line 7: arg := <-ch

Related

Why does the behavior of chan change after I use gorm to connect to the database

A normal example is this:
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
func() {
time.Sleep(1)
ch <- 1
}()
fmt.Println(<-ch)
}
The output should be:
# go run test.go
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main.func1(...)
/root/test.go:17
main.main()
/root/test.go:18 +0x47
exit status 2
But when I add the code to connect to the database like this:
package main
import (
"fmt"
"time"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func main() {
db, err := gorm.Open(mysql.Open("dsn"))
fmt.Printf("%v, %s\n", db, err)
ch := make(chan int)
func() {
time.Sleep(1)
ch <- 1
}()
fmt.Println(<-ch)
}
It doesn't report an error, it keeps blocking, the output is(I ended it with ctrl+c):
# go run test.go
&{0xc00015c510 <nil> 0 0xc00016c380 1}, %!s(<nil>)
^Csignal: interrupt
Can anyone help me, thanks.
It does not report all goroutines are asleep in case of connected DB because all goroutines are not asleep.
gorm and db start their own goroutines that are waiting to send receive, doing other stuff.
if you do a ctrl+\ in both cases these goroutines will be shown
1 No DB connected
goroutine 0 [idle]: runtime.epollwait()
/usr/lib/golang/src/runtime/sys_linux_amd64.s:699 +0x20 runtime.netpoll(0xc000032500?)
/usr/lib/golang/src/runtime/netpoll_epoll.go:126 +0xdc
DB connected
goroutine 0 [idle]:
runtime.futex()
/usr/lib/golang/src/runtime/sys_linux_amd64.s:552 +0x21
runtime.futexsleep(0x10000000000?, 0xcb927f8?, 0x7fffc45f8fa8?)
/usr/lib/golang/src/runtime/os_linux.go:66 +0x36
goroutine 1 [chan send]:
main.main.func1(...)
goroutine 19 [select]:
database/sql.(*DB).connectionOpener(0xc00019ea90, {0x81af60, 0xc0001972c0})
goroutine 20 [select]:
github.com/go-sql-driver/mysql.(*mysqlConn).startWatcher.func1()

Golang HelloActor I fatal error: all goroutines are asleep - deadlock

I have the following Code to test the actor-model with Go 1.18
package main
import (
"fmt"
"sync"
"github.com/AsynkronIT/protoactor-go/actor"
)
// Actor
type helloActor struct{}
func (*helloActor) Receive(context actor.Context) {
switch msg := context.Message().(type) {
case int:
fmt.Println(msg)
}
}
func main() {
system := actor.NewActorSystem()
props := actor.PropsFromProducer(func() actor.Actor { return &helloActor{} })
pid := system.Root.Spawn(props)
system.Root.Send(pid, 42)
system.Root.Send(pid, 42)
system.Root.Send(pid, 42)
system.Root.Send(pid, 42)
var wg sync.WaitGroup
wg.Add(1)
wg.Wait()
}
This Code was written by my professor but for some reason I get the fatal error message. Other people who have this problem often don't (properly) close channels but the actor-model does not use any.
Through debugging I found out that the programm crashes at wg.Wait(). Within the Wait-method is a call of the semaquire function. But then the programm crashes.
Here is the exact error output:
PS C:\Users\mytho\go\Verteilte Softwaresysteme\labing\ob-22ss> go run Code/proto.actor/helloworld/helloworld.go
42
42
42
42
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [semacquire]:
sync.runtime_Semacquire(0x10?)
C:/Program Files/Go/src/runtime/sema.go:56 +0x25
sync.(*WaitGroup).Wait(0xc000223320?)
C:/Program Files/Go/src/sync/waitgroup.go:136 +0x52
main.main()
C:/Users/mytho/go/Verteilte Softwaresysteme/labing/ob- 2
2ss/Code/proto.actor/helloworld/helloworld.go:34 +0x14f
goroutine 6 [chan receive]:
github.com/AsynkronIT/protoactor-go/log.(*ioLogger).listenEvent(0xc000124480)
C:/Users/mytho/go/pkg/mod/github.com/!asynkron!i!t/protoactor-go#v0.0.0-
20220403033403-f313dba2c418/log/string_encoder.go:57 +0x6d
created by github.com/AsynkronIT/protoactor-go/log.init.1
C:/Users/mytho/go/pkg/mod/github.com/!asynkron!i!t/protoactor-go#v0.0.0-
20220403033403-f313dba2c418/log/string_encoder.go:39 +0x10a
exit status 2
NOTE: the four "42" messages are only shown when the helloactor.go is debugged. When it is being runned it only shows the error-message.
var wg sync.WaitGroup
wg.Add(1)
wg.Done()
wg.Wait()
You are not calling wg.Done() to decrement the WaitGroup counter.
PS: sync.WaitGroup is used to wait for goroutines to finish before the main goroutine completes. But in your code, you are not spawning any other goroutine so it has no use.
For reference, check https://pkg.go.dev/sync#WaitGroup

golang why can not pass value to channel on the main thread

case1
package main
func main() {
dogChan := make(chan int)
dogChan <- 1
}
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/Users/xuzhongwei/Source/awesomeProject/main.go:5 +0x50
case2
package main
func main() {
dogChan := make(chan int)
go func(ch chan int) {
}(dogChan)
dogChan <- 1
}
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/Users/xuzhongwei/Source/awesomeProject/main.go:9 +0x72
case3
package main
func main() {
dogChan := make(chan int)
go func(ch chan int) {
<- ch
}(dogChan)
dogChan <- 1
}
case4
package main
func main() {
dogChan := make(chan int)
go func(ch chan int) {
<- ch
}(dogChan)
dogChan <- 1
dogChan <- 2
}
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/Users/xuzhongwei/Source/awesomeProject/main.go:10 +0x90
case5
package main
func main() {
dogChan := make(chan int)
go func(ch chan int) {
for {
select {
case <- ch:
}
}
}(dogChan)
dogChan <- 1
dogChan <- 2
dogChan <- 3
dogChan <- 4
dogChan <- 5
}
Could anyone tell me why case1, case2 got errors while case3 is ok?
In case1 my guess is that dogChan is not used in goroutine so it is treated to be closed.
In case2 my guess is that although dogChan is passed in goroutine but it is not used in goroutine so it is treated to be closed
Could anyone tell me why case4 got errors while case5 is ok?
Why do you think thats happening in case1 and case2? The channels are meant to behave as a synchronisation primitive between a sender and receiver. You have a sender sending on a channel, dogChan but none is receiving on it.
Without a receiving goroutine or a receive operation on a goroutine, the sender simply blocks (being a unbuffered channel)
Same problem on case4, you have two sends on the channel, but a single receive on the goroutine. The dogChan <- 2 will block forever. In case5, if your intention was to read from the channel, simply use a range loop to iterate over the successive values sent over it.
Golang expects program to read message(s) placed into channel.
Consumer (reader) needs to drain (read) all messages from channel, either using simple for-read, or for-select. Channel send and receive both block until sender and receiver are ready.
case1, case2 = send one message to channel, block awaiting reader, read zero messages
case4 = send one message to channel, block awaiting reader, reader does not consume (read) message
case3 = send one message to channel, consume one message from channel, sender blocks awaiting reader
case5 = send five messages to channel, consume all (five) messages, each send blocks until reader receives
// for range over channel
for msg := range ch {
// process msg
}
// for select
done := false
for !done {
select {
case msg := <-ch: {
// process msg
}
case ch == nil: {
done = true
}
}
}
// producer should close channel
close(ch)
Note:
channel can be buffered, specify a channel (queue) size
channel size default = 1 (unbuffered), writer blocks when channel full

Channel receive from just a Println in go routine throws deadlock exception

I have some code where i am trying to print the content of a channel in a goroutine using fmt.Println. Here is the simplified version of code.
package main
import "fmt"
import "time"
func main() {
ch := make(chan int)
go fmt.Println(<-ch);
ch<- 10;
time.Sleep(time.Second * 10);
}
When I run the above code I am getting this error.
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
C:/cygwin64/home/vmadhusudana/go/channel.go:9 +0x67
exit status 2
However it works fine when I call fmt.Println from a function
package main
import "fmt"
import "time"
func main() {
ch := make(chan int)
go func(){fmt.Println(<-ch)}();
ch<- 10;
time.Sleep(time.Second * 10);
}
What is making the difference here?
In the first version, the channel read is performed from the main go-routine - hence the deadlock.
The second version, the read is done from the created go-routine.
Basically this:
go fmt.Println(<-ch);
becomes:
v := <-ch
go fmt.Println(v);
As the parameters to the function are evaluated before it's invocation.
P.S. The defer statement behaves similarly. So always use a closure if you want the value passed to a go-routine or defer statement to be evaluated at "runtime".
// receive the value from channel firstly
// then create new goroutine to println
go fmt.Println(<-ch)
// receive channel in new goroutine
go func(){fmt.Println(<-ch)}()
https://play.golang.org/p/xMyqd-Yr8_a
this will help you to understand the order of exec.

Why does order and way of calling goroutines matter?

I am trying to understand goroutines.
In the following example, why do 1)--4) behave differently?
See https://play.golang.org/p/_XXZe47W53v
package main
import (
"fmt"
"time"
)
func send(x int, ch chan int) {ch<-x}
func read(ch chan int) {fmt.Println(<-ch)}
func main() {
ch := make(chan int)
go read(ch) // 1) works
go send(1,ch) // -> 1
// go fmt.Println(<-ch) // 2) fatal error: all goroutines are asleep - deadlock!
// go send(1,ch) // isn't this the same as the above ?
// go send(1,ch) // 3) works
// go fmt.Println(<-ch) // -> 1
// go fmt.Println(<-ch) // 4) fatal error: all goroutines are asleep - deadlock!
// go send(1,ch) // why does the order of the go routine calls matter?
time.Sleep(100*time.Millisecond)
}
You are seeing the errors because the read is not happening inside of the goroutine, but in the main thread.
The line:
go fmt.Println(<-ch)
is evaluating the parameter in the main thread, and once it succeeds it will run the Println in the goroutine with the already resolved parameter. Since the code can never write to the ch in this state, it deadlocks.
You can observe this by changing it to:
go func() { fmt.Println(<-ch) }()
Then it will create a closure around the ch, and then the anonymous routine will be blocked, not the main thread, which can continue on to the send().

Resources