1
0
mirror of https://github.com/golang/go synced 2024-11-19 02:14:43 -07:00

add "once" package

R=r
DELTA=79  (79 added, 0 deleted, 0 changed)
OCL=15656
CL=15656
This commit is contained in:
Russ Cox 2008-09-22 16:26:57 -07:00
parent 173ca8a2d0
commit 3c17ee69d9
2 changed files with 80 additions and 0 deletions

View File

@ -25,6 +25,7 @@ for i in \
io.go\
bufio.go\
strings.go\
once.go\
do
base=$(basename $i .go)

79
src/lib/once.go Normal file
View File

@ -0,0 +1,79 @@
// 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.
// For one-time initialization that is not done during init.
// Wrap the initialization in a niladic function f() and call
// once.Do(&f)
// If multiple processes call once.Do(&f) simultaneously
// with the same f argument, only one will call f, and the
// others will block until f finishes running.
package once
type Job struct {
done bool;
doit *chan bool; // buffer of 1
}
type Request struct {
f *();
reply *chan *Job
}
// TODO: Would like to use chan Request but 6g rejects it.
var service = new(chan *Request)
var jobmap = new(map[*()]*Job)
// Moderate access to the jobmap.
// Even if accesses were thread-safe (they should be but are not)
// something needs to serialize creation of new jobs.
// That's what the Server does.
func Server() {
for {
req := <-service;
job, present := jobmap[req.f]
if !present {
job = new(Job);
job.doit = new(chan bool, 1);
job.doit <- true;
jobmap[req.f] = job
}
req.reply <- job
}
}
export func Do(f *()) {
// Look for job in map (avoids channel communication).
// If not there, ask map server to make one.
// TODO: Uncomment use of jobmap[f] once
// maps are thread-safe.
var job *Job
var present bool
// job, present = jobmap[f]
if !present {
c := new(chan *Job);
req := Request{f, c};
service <- &req;
job = <-c
}
// Optimization
if job.done {
return
}
// If we're the first one, job.doit has a true waiting.
if <-job.doit {
f();
job.done = true
}
// Leave a false waiting for the next guy.
job.doit <- false
}
func init() {
go Server()
}