OLD | NEW |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // This package provides a single function, Do, to run a function | 5 // This package provides a single function, Do, to run a function |
6 // exactly once, usually used as part of initialization. | 6 // exactly once, usually used as part of initialization. |
7 package once | 7 package once |
8 | 8 |
9 import "sync" | 9 import "sync" |
10 | 10 |
11 type job struct { | 11 type job struct { |
12 » done» » bool; | 12 » done bool |
13 » sync.Mutex;» // should probably be sync.Notification or some such | 13 » sync.Mutex // should probably be sync.Notification or some such |
14 } | 14 } |
15 | 15 |
16 var jobs = make(map[func()]*job) | 16 var jobs = make(map[func()]*job) |
17 var joblock sync.Mutex | 17 var joblock sync.Mutex |
18 | 18 |
19 // Do is the the only exported piece of the package. | 19 // Do is the the only exported piece of the package. |
20 // For one-time initialization that is not done during init, | 20 // For one-time initialization that is not done during init, |
21 // wrap the initialization in a niladic function f() and call | 21 // wrap the initialization in a niladic function f() and call |
22 // Do(f) | 22 // Do(f) |
23 // If multiple processes call Do(f) simultaneously | 23 // If multiple processes call Do(f) simultaneously |
24 // with the same f argument, only one will call f, and the | 24 // with the same f argument, only one will call f, and the |
25 // others will block until f finishes running. | 25 // others will block until f finishes running. |
26 // | 26 // |
27 // Since a func() expression typically evaluates to a differerent | 27 // Since a func() expression typically evaluates to a differerent |
28 // function value each time it is evaluated, it is incorrect to | 28 // function value each time it is evaluated, it is incorrect to |
29 // pass such values to Do. For example, | 29 // pass such values to Do. For example, |
30 // func f(x int) { | 30 // func f(x int) { |
31 // Do(func() { fmt.Println(x) }) | 31 // Do(func() { fmt.Println(x) }) |
32 // } | 32 // } |
33 // behaves the same as | 33 // behaves the same as |
34 // func f(x int) { | 34 // func f(x int) { |
35 // fmt.Println(x) | 35 // fmt.Println(x) |
36 // } | 36 // } |
37 // because the func() expression in the first creates a new | 37 // because the func() expression in the first creates a new |
38 // func each time f runs, and each of those funcs is run once. | 38 // func each time f runs, and each of those funcs is run once. |
39 func Do(f func()) { | 39 func Do(f func()) { |
40 » joblock.Lock(); | 40 » joblock.Lock() |
41 » j, present := jobs[f]; | 41 » j, present := jobs[f] |
42 if !present { | 42 if !present { |
43 // run it | 43 // run it |
44 » » j = new(job); | 44 » » j = new(job) |
45 » » j.Lock(); | 45 » » j.Lock() |
46 » » jobs[f] = j; | 46 » » jobs[f] = j |
47 » » joblock.Unlock(); | 47 » » joblock.Unlock() |
48 » » f(); | 48 » » f() |
49 » » j.done = true; | 49 » » j.done = true |
50 » » j.Unlock(); | 50 » » j.Unlock() |
51 } else { | 51 } else { |
52 // wait for it | 52 // wait for it |
53 » » joblock.Unlock(); | 53 » » joblock.Unlock() |
54 if j.done != true { | 54 if j.done != true { |
55 » » » j.Lock(); | 55 » » » j.Lock() |
56 » » » j.Unlock(); | 56 » » » j.Unlock() |
57 } | 57 } |
58 } | 58 } |
59 } | 59 } |
OLD | NEW |