mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
sync: atomic counters
This commit is contained in:
55
vlib/sync/atomic.v
Normal file
55
vlib/sync/atomic.v
Normal file
@@ -0,0 +1,55 @@
|
||||
module sync
|
||||
|
||||
/*
|
||||
Implements the atomic operations. For now TCC does not support
|
||||
the atomic versions on nix so it uses locks to simulate the same behavor.
|
||||
On windows tcc can simulate with other atomic operations.
|
||||
|
||||
The @VROOT/thirdparty/stdatomic contains compability header files
|
||||
for stdatomic that supports both nix, windows and c++.
|
||||
|
||||
This implementations should be regarded as alpha stage and be
|
||||
further tested.
|
||||
*/
|
||||
#flag windows -I @VROOT/thirdparty/stdatomic/win
|
||||
#flag linux -I @VROOT/thirdparty/stdatomic/nix
|
||||
#flag darwin -I @VROOT/thirdparty/stdatomic/nix
|
||||
#flag freebsd -I @VROOT/thirdparty/stdatomic/nix
|
||||
#flag solaris -I @VROOT/thirdparty/stdatomic/nix
|
||||
|
||||
#include "atomic.h"
|
||||
|
||||
fn C.atomic_fetch_add_explicit() int
|
||||
fn C.atomic_fetch_sub_explicit() int
|
||||
|
||||
[typedef]
|
||||
struct C.atomic_ullong {
|
||||
}
|
||||
|
||||
[typedef]
|
||||
struct C.atomic_llong {
|
||||
}
|
||||
|
||||
// add_u64 adds provided delta as an atomic operation
|
||||
pub fn add_u64(ptr &u64, delta int) bool {
|
||||
res := C.atomic_fetch_add_explicit(&C.atomic_ullong(ptr), delta, C.NULL)
|
||||
return res == 0
|
||||
}
|
||||
|
||||
// sub_u64 subtracts provided delta as an atomic operation
|
||||
pub fn sub_u64(ptr &u64, delta int) bool {
|
||||
res := C.atomic_fetch_sub_explicit(&C.atomic_ullong(ptr), delta, C.NULL)
|
||||
return res == 0
|
||||
}
|
||||
|
||||
// add_i64 adds provided delta as an atomic operation
|
||||
pub fn add_i64(ptr &i64, delta int) bool {
|
||||
res := C.atomic_fetch_add_explicit(&C.atomic_llong(ptr), delta, C.NULL)
|
||||
return res == 0
|
||||
}
|
||||
|
||||
// add_i64 subtracts provided delta as an atomic operation
|
||||
pub fn sub_i64(ptr &i64, delta int) bool {
|
||||
res := C.atomic_fetch_sub_explicit(&C.atomic_llong(ptr), delta, C.NULL)
|
||||
return res == 0
|
||||
}
|
||||
94
vlib/sync/atomic_test.v
Normal file
94
vlib/sync/atomic_test.v
Normal file
@@ -0,0 +1,94 @@
|
||||
import sync
|
||||
|
||||
struct Counter {
|
||||
mut:
|
||||
counter u64 = 0
|
||||
}
|
||||
|
||||
// without proper syncronization this would fail
|
||||
fn test_count_100_milion_should_result_100_million() {
|
||||
mut wg := sync.new_waitgroup()
|
||||
mut counter := &Counter{}
|
||||
wg.add(10)
|
||||
for i := 0; i < 10; i++ {
|
||||
go count_ten_million(mut counter, mut wg)
|
||||
}
|
||||
wg.wait()
|
||||
assert counter.counter == 10000000
|
||||
}
|
||||
|
||||
// This test just to make sure that we have an anti-test to prove it works
|
||||
fn test_count_100_milion_should_fail_100_million_without_sync() {
|
||||
mut wg := sync.new_waitgroup()
|
||||
mut counter := &Counter{}
|
||||
wg.add(10)
|
||||
for i := 0; i < 10; i++ {
|
||||
go count_ten_million_without_sync(mut counter, mut wg)
|
||||
}
|
||||
wg.wait()
|
||||
assert counter.counter != 10000000
|
||||
}
|
||||
|
||||
fn test_count_plus_one_u64() {
|
||||
mut c := u64(0)
|
||||
sync.add_u64(&c, 1)
|
||||
assert c == 1
|
||||
}
|
||||
|
||||
fn test_count_plus_one_i64() {
|
||||
mut c := i64(0)
|
||||
sync.add_i64(&c, 1)
|
||||
assert c == 1
|
||||
}
|
||||
|
||||
fn test_count_plus_greater_than_one_u64() {
|
||||
mut c := u64(0)
|
||||
sync.add_u64(&c, 10)
|
||||
assert c == 10
|
||||
}
|
||||
|
||||
fn test_count_plus_greater_than_one_i64() {
|
||||
mut c := i64(0)
|
||||
sync.add_i64(&c, 10)
|
||||
assert c == 10
|
||||
}
|
||||
|
||||
fn test_count_minus_one_u64() {
|
||||
mut c := u64(1)
|
||||
sync.sub_u64(&c, 1)
|
||||
assert c == 0
|
||||
}
|
||||
|
||||
fn test_count_minus_one_i64() {
|
||||
mut c := i64(0)
|
||||
sync.sub_i64(&c, 1)
|
||||
assert c == -1
|
||||
}
|
||||
|
||||
fn test_count_minus_greater_than_one_u64() {
|
||||
mut c := u64(10)
|
||||
sync.sub_u64(&c, 10)
|
||||
assert c == 0
|
||||
}
|
||||
|
||||
fn test_count_minus_greater_than_one_i64() {
|
||||
mut c := i64(10)
|
||||
sync.sub_i64(&c, 20)
|
||||
assert c == -10
|
||||
}
|
||||
|
||||
// count_ten_million counts the common counter 10 million times in thread-safe way
|
||||
fn count_ten_million(mut counter Counter, mut group sync.WaitGroup) {
|
||||
for i := 0; i < 1000000; i++ {
|
||||
sync.add_u64(&counter.counter, 1)
|
||||
}
|
||||
group.done()
|
||||
}
|
||||
|
||||
// count_ten_million_without_sync counts the common counter 10 million times in none thread-safe way
|
||||
fn count_ten_million_without_sync(mut counter Counter, mut group sync.WaitGroup) {
|
||||
for i := 0; i < 1000000; i++ {
|
||||
counter.counter++
|
||||
}
|
||||
group.done()
|
||||
}
|
||||
Reference in New Issue
Block a user