Use resettable sync.Once instead of reassignment

This commit is contained in:
Ken-Håvard Lieng 2015-12-11 17:06:29 +01:00
parent 51e04c9d0f
commit 909ffd1998
7 changed files with 133 additions and 4 deletions

6
Godeps/Godeps.json generated
View File

@ -1,6 +1,6 @@
{
"ImportPath": "github.com/khlieng/dispatch",
"GoVersion": "go1.4.2",
"GoVersion": "go1.5.2",
"Packages": [
"./..."
],
@ -67,6 +67,10 @@
"Comment": "v1.5.2",
"Rev": "d5929c67198951106f49f7ea425198d0f1a08f7f"
},
{
"ImportPath": "github.com/matryer/resync",
"Rev": "3d7f7ed881e1fcb5d89be33f3eb4717ed379e7b1"
},
{
"ImportPath": "github.com/mitchellh/go-homedir",
"Rev": "1f6da4a72e57d4e7edd4a7295a585e0a3999a2d4"

View File

@ -0,0 +1,24 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof

View File

@ -0,0 +1,27 @@
# resync
`sync.Once` with `Reset()`
* See [sync.Once](http://golang.org/pkg/sync/#Once)
## Example
The following example examines how `resync.Once` could be used in a HTTP server situation.
```
// use it just like sync.Once
var once resync.Once
// handle a web request
func handleRequest(w http.ResponseWriter, r *http.Request) {
once.Do(func(){
// load templates or something
})
// TODO: respond
}
// handle some request that indicates things have changed
func handleResetRequest(w http.ResponseWriter, r *http.Request) {
once.Reset() // call Reset to cause initialisation to happen again above
}
```

View File

@ -0,0 +1,38 @@
package resync
import (
"sync"
"sync/atomic"
)
// Once is an object that will perform exactly one action
// until Reset is called.
// See http://golang.org/pkg/sync/#Once
type Once struct {
m sync.Mutex
done uint32
}
// Do simulates sync.Once.Do by executing the specified function
// only once, until Reset is called.
// See http://golang.org/pkg/sync/#Once
func (o *Once) Do(f func()) {
if atomic.LoadUint32(&o.done) == 1 {
return
}
// Slow-path.
o.m.Lock()
defer o.m.Unlock()
if o.done == 0 {
defer atomic.StoreUint32(&o.done, 1)
f()
}
}
// Reset indicates that the next call to Do should actually be called
// once again.
func (o *Once) Reset() {
o.m.Lock()
defer o.m.Unlock()
atomic.StoreUint32(&o.done, 0)
}

View File

@ -0,0 +1,35 @@
package resync_test
import (
"testing"
"github.com/cheekybits/is"
"github.com/khlieng/dispatch/Godeps/_workspace/src/github.com/matryer/resync"
)
func TestOnceReset(t *testing.T) {
is := is.New(t)
var calls int
var c resync.Once
c.Do(func() {
calls++
})
c.Do(func() {
calls++
})
c.Do(func() {
calls++
})
is.Equal(calls, 1)
c.Reset()
c.Do(func() {
calls++
})
c.Do(func() {
calls++
})
c.Do(func() {
calls++
})
is.Equal(calls, 2)
}

View File

@ -6,6 +6,8 @@ import (
"net"
"strings"
"sync"
"github.com/khlieng/dispatch/Godeps/_workspace/src/github.com/matryer/resync"
)
type Client struct {
@ -29,7 +31,7 @@ type Client struct {
quit chan struct{}
reconnect chan struct{}
ready sync.WaitGroup
once sync.Once
once resync.Once
lock sync.Mutex
}

View File

@ -6,7 +6,6 @@ import (
"fmt"
"net"
"strings"
"sync"
"time"
)
@ -107,7 +106,7 @@ func (c *Client) run() {
case <-c.reconnect:
c.reconnect = make(chan struct{})
c.once = sync.Once{}
c.once.Reset()
c.tryConnect()
}
}