| // 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, present := jobs[f] |
| if !present { |
| // 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() |
| } |
| } |
| } |