diff --git a/cmd/tools/vtest-self.v b/cmd/tools/vtest-self.v index 7162ea53d1..859029ef3f 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/many_times_test.v', 'vlib/sync/once_test.v', ] skip_on_non_windows = [ diff --git a/vlib/sync/many_times.v b/vlib/sync/many_times.v new file mode 100644 index 0000000000..286defc341 --- /dev/null +++ b/vlib/sync/many_times.v @@ -0,0 +1,36 @@ +module sync + +import sync.atomic2 + +pub struct ManyTimes { +mut: + m RwMutex +pub: + times u64 = 1 + count u64 +} + +// new_many_times return a new ManyTimes struct. +pub fn new_many_times(times u64) &ManyTimes { + mut many_times := &ManyTimes{ + times: times + } + many_times.m.init() + return many_times +} + +// do execute the function only setting times. +pub fn (mut m ManyTimes) do(f fn ()) { + if atomic2.load_u64(&m.count) < m.times { + m.do_slow(f) + } +} + +fn (mut m ManyTimes) do_slow(f fn ()) { + m.m.@lock() + if m.count < m.times { + atomic2.store_u64(&m.count, m.count + 1) + f() + } + m.m.unlock() +} diff --git a/vlib/sync/many_times_test.v b/vlib/sync/many_times_test.v new file mode 100644 index 0000000000..e2ddca3ae1 --- /dev/null +++ b/vlib/sync/many_times_test.v @@ -0,0 +1,49 @@ +import sync + +struct Counter { +pub mut: + i int +} + +fn (mut c Counter) add(i int) { + c.i = c.i + i +} + +fn run(mut m sync.ManyTimes, mut co Counter, c chan bool) { + m.do(fn [mut co] () { + co.add(5) + }) + c <- true +} + +fn test_many_times_once() { + mut co := &Counter{} + mut m := sync.new_many_times(1) + c := chan bool{} + n := 10 + + // It is executed 10 times, but only once actually. + for i := 0; i < n; i++ { + go run(mut m, mut co, c) + } + for i := 0; i < n; i++ { + <-c + } + assert co.i == 5 +} + +fn test_many_times_fifth() { + mut co := &Counter{} + mut m := sync.new_many_times(5) + c := chan bool{} + n := 10 + + // It is executed 10 times, but only 5 times actually. + for i := 0; i < n; i++ { + go run(mut m, mut co, c) + } + for i := 0; i < n; i++ { + <-c + } + assert co.i == 25 +}