Skip to content

Instantly share code, notes, and snippets.

@win-t
Last active April 12, 2022 02:26
Show Gist options
  • Save win-t/7ae0ab5fdea1f92c5bf4f96b87551996 to your computer and use it in GitHub Desktop.
Save win-t/7ae0ab5fdea1f92c5bf4f96b87551996 to your computer and use it in GitHub Desktop.
golang owned goroutine
package resource
import (
"context"
"fmt"
"io"
"runtime"
"sync/atomic"
"time"
)
type Resource struct {
// we embed the inner representation, so all public method is also available in outer one
*resource
}
// this is inner representation of the resource
type resource struct {
ctx context.Context
cancel context.CancelFunc
counter int32
}
// compile time check to make sure *Resource implement io.Closer
var _ io.Closer = (*Resource)(nil)
func (r *resource) Close() error { r.cancel(); return nil }
func (r *resource) main() {
fmt.Println("resource start")
defer fmt.Println("resource end")
for {
select {
case <-r.ctx.Done():
return
case <-time.After(1 * time.Second):
}
r.PrintInc()
}
}
func (i *resource) PrintInc() {
fmt.Println("Hello", atomic.AddInt32(&i.counter, 1))
}
func NewResource() *Resource {
ctx, cancel := context.WithCancel(context.Background())
ret := &Resource{&resource{ctx, cancel, 0}}
runtime.SetFinalizer(ret, (*Resource).Close)
go ret.resource.main()
return ret
}
@win-t
Copy link
Author

win-t commented Apr 12, 2022

most golang resources (like files, socket, database connection) will be automatically closed when GC kick-in,
but, the GC cannot collect any object that is referenced by any goroutine
so, the GC itself cannot collect any resource that has a goroutine attached to them,
one solution is to wrap it behind another pointer, so when the outer pointer is collected, it will close the inner goroutine

for example

func main() {
	resource.NewResource()
	// ops, we forgot to defer close it

	time.Sleep(5 * time.Second)
	runtime.GC()
	runtime.GC()
	time.Sleep(1 * time.Second)
}

will output

resource start
Hello 1
Hello 2
Hello 3
Hello 4
Hello 5
resource end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment