| // 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. | |
| // This package provides a single function, Do, to run a function | |
| // exactly once, usually used as part of initialization. | |
| package once | |
| import "sync" | |
| type job struct { | |
| done bool | |
| sync.Mutex // should probably be sync.Notification or some such | |
| } | |
| var jobs = make(map[func()]*job) | |
| var joblock sync.Mutex | |
| // Do is the the only exported piece of the package. | |
| // For one-time initialization that is not done during init, | |
| // wrap the initialization in a niladic function f() and call | |
| // Do(f) | |
| // If multiple processes call Do(f) simultaneously | |
| // with the same f argument, only one will call f, and the | |
| // others will block until f finishes running. | |
| // | |
| // Since a func() expression typically evaluates to a differerent | |
| // function value each time it is evaluated, it is incorrect to | |
| // pass such values to Do. For example, | |
| // func f(x int) { | |
| // Do(func() { fmt.Println(x) }) | |
| // } | |
| // behaves the same as | |
| // func f(x int) { | |
| // fmt.Println(x) | |
| // } | |
| // because the func() expression in the first creates a new | |
| // func each time f runs, and each of those funcs is run once. | |
| func Do(f func()) { | |
| joblock.Lock() | |
| j := jobs[f] | |
| if j == nil { | |
| // run it | |
| j = new(job) | |
| j.Lock() | |
| jobs[f] = j | |
| joblock.Unlock() | |
| f() | |
| j.done = true | |
| j.Unlock() | |
| } else { | |
| // wait for it | |
| joblock.Unlock() | |
| if j.done != true { | |
| j.Lock() | |
| j.Unlock() | |
| } | |
| } | |
| } |