Panic in goroutines

7,578 views
Skip to first unread message

karla

unread,
Feb 27, 2011, 9:48:42 PM2/27/11
to golang-nuts
Hello, I'm not entirely happy about the program behavior when
exceptions (panic ()) are thrown in goroutines. Certainly, if one
calls panic () is done in a goroutine daughter of main (), the whole
program hood, including the main ()? Why? I've tried to push it, but
have not had a satisfactory result. For example:

package main
import ("time";"fmt")

func c(msg string){
time.Sleep(4*1e9)
if x := recover(); x!=nil{
fmt.Println(msg, x)
}else fmt.Println(msg, "No Panics")
}

func a(msg string, sec int64) {
defer c(msg)

time.Sleep(sec *1e9)
fmt.Println(msg, "is ready")
}
func b(){
defer c("b()")

go func(){
go func (){
go func(){
go func(){
go func(){
go func(){
go func(){
go func(){
go func() {
go func() {
go func(){ panic("panicking")
}()
}()
}()
}()
}()
}()
}()
}()
}()
}()
}()
go a("tea", 3)
go a("coffee", 2)

}
func main(){
fmt.Println("Antes...")
defer c("main")
go b()
time.Sleep(4*1e9)
fmt.Println("Fim...")
}


A saída é:


Antes...
panic: panicking

runtime.panic+0x99 /go/src/pkg/runtime/proc.c:1023
runtime.panic(0x447574, 0x10b904d0)
main._func_011+0x46 C:/Go/test/concurrency/Casos/con2.0.go:30
main._func_011()
runtime.goexit /go/src/pkg/runtime/proc.c:149
runtime.goexit()

goroutine 5 [3]:
runtime.entersyscall+0x24 /go/src/pkg/runtime/proc.c:577
runtime.entersyscall()
runtime.syscall+0x8c /go/src/pkg/runtime/windows/thread.c:240
runtime.syscall(0x757aef66, 0x1, 0x30c6a4, 0x30c6b8,
0xffffffff, ...)
syscall.Syscall+0x40 /go/src/pkg/runtime/windows/syscall.c:36
syscall.Syscall(0x757aef66, 0x1, 0x7d0, 0x0, 0x0, ...)
syscall.sleep+0x4a c:/go/src/pkg/syscall/zsyscall_windows_386.go:455
syscall.sleep(0x7d0, 0x0)
syscall.Sleep+0x65 c:/go/src/pkg/syscall/syscall_windows.go:435
syscall.Sleep(0x77359400, 0x0, 0x10bd2bc0, 0x20)
time.sleep+0x62 c:/go/src/pkg/time/sleep.go:65
time.sleep(0x9fbd0f78, 0x12067ad8, 0x77359400, 0x0, 0x0, ...)
time.Sleep+0x44 c:/go/src/pkg/time/sleep.go:54
time.Sleep(0x77359400, 0x0, 0x0, 0x0)
main.a+0x63 C:/Go/test/concurrency/Casos/con2.0.go:14
main.a(0x43cae4, 0x6, 0x2, 0x0)
runtime.goexit /go/src/pkg/runtime/proc.c:149
runtime.goexit()

goroutine 4 [3]:
runtime.entersyscall+0x24 /go/src/pkg/runtime/proc.c:577
runtime.entersyscall()
runtime.syscall+0x8c /go/src/pkg/runtime/windows/thread.c:240
runtime.syscall(0x757aef66, 0x1, 0x309ea4, 0x309eb8, 0x0, ...)
syscall.Syscall+0x40 /go/src/pkg/runtime/windows/syscall.c:36
syscall.Syscall(0x757aef66, 0x1, 0xbb8, 0x0, 0x0, ...)
syscall.sleep+0x4a c:/go/src/pkg/syscall/zsyscall_windows_386.go:455
syscall.sleep(0xbb8, 0x0)
syscall.Sleep+0x65 c:/go/src/pkg/syscall/syscall_windows.go:435
syscall.Sleep(0xb2d05e00, 0x0, 0x10b94c20, 0x20)
time.sleep+0x62 c:/go/src/pkg/time/sleep.go:65
time.sleep(0x9f8f44d0, 0x12067ad8, 0xb2d05e00, 0x0, 0x0, ...)
time.Sleep+0x44 c:/go/src/pkg/time/sleep.go:54
time.Sleep(0xb2d05e00, 0x0, 0x0, 0x0)
main.a+0x63 C:/Go/test/concurrency/Casos/con2.0.go:14
main.a(0x43c2d8, 0x3, 0x3, 0x0)
runtime.goexit /go/src/pkg/runtime/proc.c:149
runtime.goexit()

goroutine 2 [3]:
runtime.entersyscall+0x24 /go/src/pkg/runtime/proc.c:577
runtime.entersyscall()
runtime.syscall+0x8c /go/src/pkg/runtime/windows/thread.c:240
runtime.syscall(0x757aef66, 0x1, 0x304e44, 0x304e58,
0xffffffff, ...)
syscall.Syscall+0x40 /go/src/pkg/runtime/windows/syscall.c:36
syscall.Syscall(0x757aef66, 0x1, 0xfa0, 0x0, 0x0, ...)
syscall.sleep+0x4a c:/go/src/pkg/syscall/zsyscall_windows_386.go:455
syscall.sleep(0xfa0, 0x0)
syscall.Sleep+0x65 c:/go/src/pkg/syscall/syscall_windows.go:435
syscall.Sleep(0xee6b2800, 0x0, 0x40a71e, 0x4e9b38)
time.sleep+0x62 c:/go/src/pkg/time/sleep.go:65
time.sleep(0x9f8f44d0, 0x12067ad8, 0xee6b2800, 0x0,
0x40d6f9, ...)
time.Sleep+0x44 c:/go/src/pkg/time/sleep.go:54
time.Sleep(0xee6b2800, 0x0, 0x4108f9, 0x1)
main.c+0x37 C:/Go/test/concurrency/Casos/con2.0.go:5
main.c(0x43c274, 0x3)
main.b+0xb0 C:/Go/test/concurrency/Casos/con2.0.go:43
main.b()
runtime.goexit /go/src/pkg/runtime/proc.c:149
runtime.goexit()

goroutine 1 [3]:
runtime.entersyscall+0x24 /go/src/pkg/runtime/proc.c:577
runtime.entersyscall()
runtime.syscall+0x8c /go/src/pkg/runtime/windows/thread.c:240
runtime.syscall(0x757aef66, 0x1, 0x302698, 0x3026ac,
0x40d6f9, ...)
syscall.Syscall+0x40 /go/src/pkg/runtime/windows/syscall.c:36
syscall.Syscall(0x757aef66, 0x1, 0xfa0, 0x0, 0x0, ...)
syscall.sleep+0x4a c:/go/src/pkg/syscall/zsyscall_windows_386.go:455
syscall.sleep(0xfa0, 0x0)
syscall.Sleep+0x65 c:/go/src/pkg/syscall/syscall_windows.go:435
syscall.Sleep(0xee6b2800, 0x0, 0x410822, 0x4eb268)
time.sleep+0x62 c:/go/src/pkg/time/sleep.go:65
time.sleep(0x9cff1c40, 0x12067ad8, 0xee6b2800, 0x0,
0x40c69b, ...)
time.Sleep+0x44 c:/go/src/pkg/time/sleep.go:54
time.Sleep(0xee6b2800, 0x0, 0x1, 0x9)
main.main+0xbc C:/Go/test/concurrency/Casos/con2.0.go:50
main.main()
runtime.mainstart+0xf 386/asm.s:93
runtime.mainstart()
runtime.goexit /go/src/pkg/runtime/proc.c:149
runtime.goexit()


Why not just die goroutine opening the panic ()? And why not put off
in other handler functions goroutines are not able to run normally and
catch the exception, as in a sequential execution?

Karla Tahan

unread,
Feb 27, 2011, 9:58:09 PM2/27/11
to golang-nuts
Excuse my English, but replace the word "hood" with the word "die" ...

Karla Polyana Silva Falcão

Computer

Contact me: Google Talk/ karla...@gmail.com Skype/ karlatahan MSN/ k....@hotmail.com


2011/2/27 karla <karla...@gmail.com>

Andrew Gerrand

unread,
Feb 27, 2011, 10:07:09 PM2/27/11
to karla, golang-nuts
This is the expected behavior.

"When a function F calls panic, normal execution of F stops
immediately. Any functions whose execution was deferred by the
invocation of F are run in the usual way, and then F returns to its
caller. To the caller, F then behaves like a call to panic,
terminating its own execution and running deferred functions. This
continues until all functions in the goroutine have ceased execution,
in reverse order. At that point, the program is terminated and the
error condition is reported, including the value of the argument to
panic. This termination sequence is called panicking."
- http://golang.org/doc/go_spec.html#Handling_panics

All that nesting is not doing what you think it is, either. There is
no hierarchy amongst goroutines. Once you launch a goroutine it exists
on its own, untethered to its calling goroutine.

You can achieve the same effect with simply:


go func(){ panic("panicking") }()

For more on panics, see this blog post:
http://blog.golang.org/2010/08/defer-panic-and-recover.html

Andrew

Steven

unread,
Feb 27, 2011, 10:14:07 PM2/27/11
to Karla Tahan, golang-nuts
When a panic occurs, it means something has gone very, very wrong. You can't know that the goroutine dying doesn't impact other goroutines. As such the panic brings down your entire program. If you want to isolate a goroutine, you can defer a recover at the beginning. This gives you control over how to handle failure.

Ian Lance Taylor

unread,
Feb 28, 2011, 11:49:14 AM2/28/11
to karla, golang-nuts
karla <karla...@gmail.com> writes:

> Hello, I'm not entirely happy about the program behavior when
> exceptions (panic ()) are thrown in goroutines. Certainly, if one
> calls panic () is done in a goroutine daughter of main (), the whole
> program hood, including the main ()? Why? I've tried to push it, but
> have not had a satisfactory result. For example:

The current system is flexible. For example, you may prefer doing
something like this:

package mygo
import "fmt"
func MyGo(f func()) {
go func() {
defer func() {
if r := recover(); r != nil {
fmt.Println("goroutine paniced:", r)
}
}()
f()
}()
}

Ian

Karla Tahan

unread,
Feb 28, 2011, 6:55:19 PM2/28/11
to Ian Lance Taylor, golang-nuts
Yes, east aware of this so flexible that you are talking about.

But do not feel right for a good mechanism for handling exceptions, the functions are not treated equally both sequentially and in parallel when they are in panic (). If sequentially, exceptions are propagated and can be addressed in the above scopes. In parallel, my view, when a goroutine are panicking, they should die silently without icomodar other ...

I think it is missing a further specification for exception handling in concurrent Go I'm working on this. Prior to August 2010 aimed at creating one, but as has already been created, I intend to improve it. So I am studying in depth the current mechanism and came across these strange events, I want to clarify them here.


Karla Polyana Silva Falcão

Computer

Contact me: Google Talk/ karla...@gmail.com Skype/ karlatahan MSN/ k....@hotmail.com


2011/2/28 Ian Lance Taylor <ia...@google.com>

Ian Lance Taylor

unread,
Feb 28, 2011, 7:20:30 PM2/28/11
to Karla Tahan, golang-nuts
Karla Tahan <karla...@gmail.com> writes:

> But do not feel right for a good mechanism for handling exceptions, the
> functions are not treated equally both sequentially and in parallel when
> they are in panic (). If sequentially, exceptions are propagated and can be
> addressed in the above scopes. In parallel, my view, when a goroutine are
> panicking, they should die silently without icomodar other ...

Sometimes that is what you want, sometimes it isn't. With the current
approach, you can get what you want with a little extra work. If your
proposal were the default, we would need extra mechanisms to get the
current approach.

Ian

Karla Tahan

unread,
Feb 28, 2011, 7:27:10 PM2/28/11
to Ian Lance Taylor, golang-nuts
Sure, but our work involves just that, efficiency, speed and comfort for developers using the tools of language!
Thanks for everything.


Karla Polyana Silva Falcão

Computer

Contact me: Google Talk/ karla...@gmail.com Skype/ karlatahan MSN/ k....@hotmail.com


2011/2/28 Ian Lance Taylor <ia...@google.com>
Karla Tahan <karla...@gmail.com> writes:

SnakE

unread,
Mar 5, 2011, 10:54:01 AM3/5/11
to golang-nuts
2011/3/1 Karla Tahan <karla...@gmail.com>

Sure, but our work involves just that, efficiency, speed and comfort for developers using the tools of language!
Thanks for everything.

package main

import (
"fmt"
"time"
)

func main() {
goSilent(func() { panic("panicking") })
time.Sleep(1000 * 1000 * 1000)
}

func goSilent(f func()) {
defer func() {
if p := recover(); p != nil {
fmt.Println("Panic silenced:", p)
}
}()
f()
}

Looks easy enough to me.

SnakE

unread,
Mar 5, 2011, 11:17:26 AM3/5/11
to golang-nuts
2011/3/5 SnakE <snake...@gmail.com>
This was of course wrong, I forgot to start the goroutine.  Here's the fixed version.

package main

import (
"fmt"
"time"
)

func main() {
goSilent(func() { panic("panicking") })
time.Sleep(1000 * 1000 * 1000)
}

func goSilent(f func()) {
go func() {
defer func() {
if p := recover(); p != nil {
fmt.Println("Panic silenced:", p)
}
}()
f()
}()
}

Reply all
Reply to author
Forward
0 new messages