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:
parent
173ca8a2d0
commit
3c17ee69d9
@ -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
79
src/lib/once.go
Normal 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()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user