Leaking Goroutines

1756 views
Skip to first unread message

Paul Lalonde

unread,
Aug 16, 2011, 5:54:11 PM8/16/11
to golan...@googlegroups.com
I'm maintaining a list of servers that have been discovered within some timeout; when the timer expires, I want to remove the server from the list.  If the server sends its renewal in time I want to reset the timer - the obvious way is to create a new timer for that record.
Will the goroutine blocked in the channel read of the old timer be garbage collected when I lose the reference to it (the channel it's waiting on)?
Is there a better idiom for this?

Sketch of the code:
type Server {
    addr string
    stale time.Timer
}
var servers map[string]*Server

func AddServer(addr string)
  server, present := servers[addr]
  if present {
    server.stale.Stop()
  }
  server = &Server{addr, time.NewTimer(TIMEOUT)}
  go func() {
    _ = <- server.stale.C
    servers[addr] = cs.servers[addr], false
  }
}

Paul

Russ Cox

unread,
Aug 16, 2011, 6:36:04 PM8/16/11
to golan...@googlegroups.com
goroutines are not garbage collected.
You need to make the goroutine return.
Usually that is done with a select.
Note that a *time.Timer has a Stop method.

Russ

Brad Fitzpatrick

unread,
Aug 16, 2011, 6:38:07 PM8/16/11
to golan...@googlegroups.com
You could add a *time.Timer field to your Server struct, created like:

server.timeout = time.AfterFunc(10e9, func() {
     markServerDead(server)
})

Then whenever you get a heartbeat, you can server.timeout.Stop() and re-initialize it.

Paul Lalonde

unread,
Aug 17, 2011, 8:34:15 AM8/17/11
to golang-nuts


On Aug 16, 3:38 pm, Brad Fitzpatrick <bradf...@google.com> wrote:
> server.timeout = time.AfterFunc(10e9, func() {
>      markServerDead(server)

AfterFunc is exactly the right thing. Reading the implementation it
doesn't rely on leaking goroutines to do this.

Thanks,
Paul

unread,
Aug 17, 2011, 10:57:31 AM8/17/11
to golang-nuts
On Aug 17, 12:36 am, Russ Cox <r...@golang.org> wrote:
> goroutines are not garbage collected.

This is an interesting problem. The Go run-time currently implements a
partial garbage collection of goroutines - when it detects that all
goroutines can be "garbage collected" it reports a deadlock and
terminates the whole program.

Generally, if a goroutine is waiting on a resource (that is: waiting
for the resource to change its state), and the run-time detects that
the program has no way of changing the resource's state, then the
goroutine will block forever.

Option 1: Some people will say that a forever-blocked goroutine should
be silently removed by the garbage collector.

Option 2: Some people will say that it is a run-time error, because a
goroutine is an active entity. When a goroutine wants to terminate, it
willingly exits from its main function. Until it exits from its main
function, it doesn't want to be terminated and therefore an error
should be reported when the run-time detects the goroutine is blocked
forever.

The Go run-time currently implements neither option. (It only
implements a special case of option 2.)

Russ Cox

unread,
Aug 17, 2011, 1:24:41 PM8/17/11
to ⚛, golang-nuts
On Wed, Aug 17, 2011 at 10:57, ⚛ <0xe2.0x...@gmail.com> wrote:
> On Aug 17, 12:36 am, Russ Cox <r...@golang.org> wrote:
>> goroutines are not garbage collected.
>
> This is an interesting problem. The Go run-time currently implements a
> partial garbage collection of goroutines - when it detects that all
> goroutines can be "garbage collected" it reports a deadlock and
> terminates the whole program.
>
> Generally, if a goroutine is waiting on a resource (that is: waiting
> for the resource to change its state), and the run-time detects that
> the program has no way of changing the resource's state, then the
> goroutine will block forever.
>
> Option 1: Some people will say that a forever-blocked goroutine should
> be silently removed by the garbage collector.
>
> Option 2: Some people will say that it is a run-time error, because a
> goroutine is an active entity. When a goroutine wants to terminate, it
> willingly exits from its main function. Until it exits from its main
> function, it doesn't want to be terminated and therefore an error
> should be reported when the run-time detects the goroutine is blocked
> forever.

We're not likely to do either of these.
If a program is blocked forever, there is
very little point to letting it continue to
sit there. If a single goroutine is blocked
forever, things are much less clear-cut.
It is also very hard to tell that a single
goroutine is blocked forever in most cases.

Option 1 makes debugging too hard.

Option 2 would break many valid Go programs,
for example all the programs that block main
by using select{}.

Russ

Reply all
Reply to author
Forward
0 new messages