diff --git a/cmd/tools/vtest-self.v b/cmd/tools/vtest-self.v index 65a9316b91..7162ea53d1 100644 --- a/cmd/tools/vtest-self.v +++ b/cmd/tools/vtest-self.v @@ -115,6 +115,7 @@ const ( 'vlib/vweb/request_test.v', 'vlib/net/http/request_test.v', 'vlib/vweb/route_test.v', + 'vlib/sync/once_test.v', ] skip_on_non_windows = [ 'do_not_remove', diff --git a/vlib/sync/once.v b/vlib/sync/once.v new file mode 100644 index 0000000000..235bfdaf62 --- /dev/null +++ b/vlib/sync/once.v @@ -0,0 +1,33 @@ +module sync + +import sync.atomic2 + +pub struct Once { +mut: + m RwMutex +pub: + count u64 +} + +// new_once return a new Once struct. +pub fn new_once() &Once { + mut once := &Once{} + once.m.init() + return once +} + +// do execute the function only once. +pub fn (mut o Once) do(f fn ()) { + if atomic2.load_u64(&o.count) < 1 { + o.do_slow(f) + } +} + +fn (mut o Once) do_slow(f fn ()) { + o.m.@lock() + if o.count < 1 { + atomic2.store_u64(&o.count, 1) + f() + } + o.m.unlock() +} diff --git a/vlib/sync/once_test.v b/vlib/sync/once_test.v new file mode 100644 index 0000000000..5b77c84dd1 --- /dev/null +++ b/vlib/sync/once_test.v @@ -0,0 +1,33 @@ +import sync + +struct One { +pub mut: + i int +} + +fn (mut o One) add(i int) { + o.i = o.i + i +} + +fn run(mut once sync.Once, mut o One, c chan bool) { + once.do(fn [mut o] () { + o.add(5) + }) + c <- true +} + +fn test_once() { + mut o := &One{} + mut once := sync.new_once() + c := chan bool{} + n := 10 + + // It is executed 10 times, but only once actually. + for i := 0; i < n; i++ { + go run(mut once, mut o, c) + } + for i := 0; i < n; i++ { + <-c + } + assert o.i == 5 +}