]> Cypherpunks repositories - gostls13.git/commitdiff
sync: add sync.Once, a proposed replacement for package once.
authorRob Pike <r@golang.org>
Thu, 5 Aug 2010 03:31:10 +0000 (13:31 +1000)
committerRob Pike <r@golang.org>
Thu, 5 Aug 2010 03:31:10 +0000 (13:31 +1000)
This implementation is simpler and more useful, since it can work
with methods.

R=rsc
CC=golang-dev
https://golang.org/cl/1864051

src/pkg/sync/Makefile
src/pkg/sync/mutex.go
src/pkg/sync/once.go [new file with mode: 0644]
src/pkg/sync/once_test.go [new file with mode: 0644]

index 4b9a05816d14e7ae987bd6ed0f87cb855b7b5764..dc3a4b442d923e59267268bad0d548a62a7ae5b1 100644 (file)
@@ -7,6 +7,7 @@ include ../../Make.$(GOARCH)
 TARG=sync
 GOFILES=\
        mutex.go\
+       once.go \
        rwmutex.go\
 
 # 386-specific object files
index b170370bc1ff02011ff78abfa422b2d17f2d7d23..9a2bb2bb4f548b6701dd361d68f01492e52308d0 100644 (file)
@@ -3,9 +3,10 @@
 // license that can be found in the LICENSE file.
 
 // The sync package provides basic synchronization primitives
-// such as mutual exclusion locks.  These are intended for use
-// by low-level library routines.  Higher-level synchronization
-// is better done via channels and communication.
+// such as mutual exclusion locks.  Other than the Once type,
+// most are intended for use by low-level library routines.
+// Higher-level synchronization  is better done via channels
+// and communication.
 package sync
 
 import "runtime"
diff --git a/src/pkg/sync/once.go b/src/pkg/sync/once.go
new file mode 100644 (file)
index 0000000..298d8e8
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sync
+
+// Once is an object that will perform exactly one action.
+type Once struct {
+       m    Mutex
+       done bool
+}
+
+// Do calls the function f if and only if the method is being called for the
+// first time with this receiver.  In other words, given
+//     var once Once
+// if once.Do(f) is called multiple times, only the first call will invoke f,
+// even if f has a different value in each invocation.  A new instance of
+// Once is required for each function to execute.
+//
+// Do is intended for initialization that must be run exactly once.  Since f
+// is niladic, it may be necessary to use a function literal to capture the
+// arguments to a function to be invoked by Do:
+//     config.once.Do(func() { config.init(filename) })
+//
+func (o *Once) Do(f func()) {
+       o.m.Lock()
+       defer o.m.Unlock()
+       if !o.done {
+               o.done = true
+               f()
+       }
+}
diff --git a/src/pkg/sync/once_test.go b/src/pkg/sync/once_test.go
new file mode 100644 (file)
index 0000000..155954a
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sync_test
+
+import (
+       . "sync"
+       "testing"
+)
+
+type one int
+
+func (o *one) Increment() {
+       *o++
+}
+
+func run(once *Once, o *one, c chan bool) {
+       once.Do(func() { o.Increment() })
+       c <- true
+}
+
+func TestOnce(t *testing.T) {
+       o := new(one)
+       once := new(Once)
+       c := make(chan bool)
+       const N = 10
+       for i := 0; i < N; i++ {
+               go run(once, o, c)
+       }
+       for i := 0; i < N; i++ {
+               <-c
+       }
+       if *o != 1 {
+               t.Errorf("once failed: %d is not 1", *o)
+       }
+}