mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen: add support for shared arrays (#5721)
This commit is contained in:
parent
38000f8622
commit
88248b1b66
@ -2376,10 +2376,17 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
|
||||
if g.is_assign_lhs && !is_selector && node.is_setter {
|
||||
g.is_array_set = true
|
||||
g.write('array_set(')
|
||||
if !left_is_ptr {
|
||||
if !left_is_ptr || node.left_type.has_flag(.shared_f) {
|
||||
g.write('&')
|
||||
}
|
||||
g.expr(node.left)
|
||||
if node.left_type.has_flag(.shared_f) {
|
||||
if left_is_ptr {
|
||||
g.write('->val')
|
||||
} else {
|
||||
g.write('.val')
|
||||
}
|
||||
}
|
||||
g.write(', ')
|
||||
g.expr(node.index)
|
||||
mut need_wrapper := true
|
||||
@ -2404,10 +2411,17 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
|
||||
info.elem_type != table.string_type {
|
||||
// TODO move this
|
||||
g.write('*($elem_type_str*)array_get(')
|
||||
if left_is_ptr {
|
||||
if left_is_ptr && !node.left_type.has_flag(.shared_f) {
|
||||
g.write('*')
|
||||
}
|
||||
g.expr(node.left)
|
||||
if node.left_type.has_flag(.shared_f) {
|
||||
if left_is_ptr {
|
||||
g.write('->val')
|
||||
} else {
|
||||
g.write('.val')
|
||||
}
|
||||
}
|
||||
g.write(', ')
|
||||
g.expr(node.index)
|
||||
g.write(') ')
|
||||
@ -2428,10 +2442,17 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
|
||||
}
|
||||
} else {
|
||||
g.write('(*($elem_type_str*)array_get(')
|
||||
if left_is_ptr {
|
||||
if left_is_ptr && !node.left_type.has_flag(.shared_f) {
|
||||
g.write('*')
|
||||
}
|
||||
g.expr(node.left)
|
||||
if node.left_type.has_flag(.shared_f) {
|
||||
if left_is_ptr {
|
||||
g.write('->val')
|
||||
} else {
|
||||
g.write('.val')
|
||||
}
|
||||
}
|
||||
g.write(', ')
|
||||
g.expr(node.index)
|
||||
g.write('))')
|
||||
@ -4497,6 +4518,24 @@ _Interface* I_${cctype}_to_Interface_${interface_name}_ptr($cctype* x) {
|
||||
|
||||
fn (mut g Gen) array_init(it ast.ArrayInit) {
|
||||
type_sym := g.table.get_type_symbol(it.typ)
|
||||
styp := g.typ(it.typ)
|
||||
mut shared_styp := '' // only needed for shared &[]{...}
|
||||
is_amp := g.is_amp
|
||||
g.is_amp = false
|
||||
if is_amp {
|
||||
g.out.go_back(1) // delete the `&` already generated in `prefix_expr()
|
||||
if g.is_shared {
|
||||
mut shared_typ := it.typ.set_flag(.shared_f)
|
||||
shared_styp = g.typ(shared_typ)
|
||||
g.writeln('($shared_styp*)memdup(&($shared_styp){.val = ')
|
||||
} else {
|
||||
g.write('($styp*)memdup(&') // TODO: doesn't work with every compiler
|
||||
}
|
||||
} else {
|
||||
if g.is_shared {
|
||||
g.writeln('{.val = ($styp*)')
|
||||
}
|
||||
}
|
||||
if type_sym.kind == .array_fixed {
|
||||
g.write('{')
|
||||
for i, expr in it.exprs {
|
||||
@ -4568,6 +4607,14 @@ fn (mut g Gen) array_init(it ast.ArrayInit) {
|
||||
}
|
||||
}
|
||||
g.write('}))')
|
||||
if g.is_shared {
|
||||
g.write(', .mtx = sync__new_rwmutex()}')
|
||||
if is_amp {
|
||||
g.write(', sizeof($shared_styp))')
|
||||
}
|
||||
} else if is_amp {
|
||||
g.write(', sizeof($styp))')
|
||||
}
|
||||
}
|
||||
|
||||
// `ui.foo(button)` =>
|
||||
|
41
vlib/v/tests/shared_array_test.v
Normal file
41
vlib/v/tests/shared_array_test.v
Normal file
@ -0,0 +1,41 @@
|
||||
import sync
|
||||
import time
|
||||
|
||||
fn incr(shared foo []int, index int) {
|
||||
for _ in 0 .. 100000 {
|
||||
lock foo {
|
||||
foo[index] = foo[index] + 1
|
||||
}
|
||||
}
|
||||
lock foo {
|
||||
foo[2]++
|
||||
}
|
||||
}
|
||||
|
||||
fn test_shared_array() {
|
||||
shared foo := &[10, 20, 0]
|
||||
go incr(shared foo, 0)
|
||||
go incr(shared foo, 1)
|
||||
go incr(shared foo, 0)
|
||||
go incr(shared foo, 1)
|
||||
for _ in 0 .. 50000 {
|
||||
lock foo {
|
||||
foo[0] -= 2
|
||||
foo[1] += 3
|
||||
}
|
||||
}
|
||||
mut finished_threads := 0
|
||||
for {
|
||||
rlock foo {
|
||||
finished_threads = foo[2]
|
||||
}
|
||||
if finished_threads == 4 {
|
||||
break
|
||||
}
|
||||
time.sleep_ms(100)
|
||||
}
|
||||
rlock foo {
|
||||
assert foo[0] == 100010
|
||||
assert foo[1] == 350020
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ mut:
|
||||
}
|
||||
|
||||
fn (shared x St) f(shared y St, shared z St) {
|
||||
for _ in 0..101 {
|
||||
for _ in 0 .. 101 {
|
||||
lock x, y {
|
||||
tmp := y.a
|
||||
y.a = x.a
|
||||
@ -30,7 +30,7 @@ fn test_shared_receiver_lock() {
|
||||
a: 1
|
||||
}
|
||||
go x.f(shared y, shared z)
|
||||
for _ in 0..100 {
|
||||
for _ in 0 .. 100 {
|
||||
lock x, y {
|
||||
tmp := x.a
|
||||
x.a = y.a
|
||||
@ -38,8 +38,8 @@ fn test_shared_receiver_lock() {
|
||||
}
|
||||
}
|
||||
// the following would be a good application for a channel
|
||||
for finished := false; ; {
|
||||
lock z {
|
||||
for finished := false; true; {
|
||||
rlock z {
|
||||
finished = z.a == 0
|
||||
}
|
||||
if finished {
|
||||
@ -47,7 +47,7 @@ fn test_shared_receiver_lock() {
|
||||
}
|
||||
time.sleep_ms(100)
|
||||
}
|
||||
lock x, y {
|
||||
rlock x, y {
|
||||
assert x.a == 7 && y.a == 5
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ mut:
|
||||
}
|
||||
|
||||
fn f(shared x St, shared z St) {
|
||||
for _ in 0..reads_per_thread {
|
||||
for _ in 0 .. reads_per_thread {
|
||||
rlock x { // other instances may read at the same time
|
||||
time.sleep_ms(1)
|
||||
assert x.a == 7 || x.a == 5
|
||||
@ -20,8 +20,8 @@ fn f(shared x St, shared z St) {
|
||||
|
||||
const (
|
||||
reads_per_thread = 30
|
||||
read_threads = 10
|
||||
writes = 5
|
||||
read_threads = 10
|
||||
writes = 5
|
||||
)
|
||||
|
||||
fn test_shared_lock() {
|
||||
@ -32,21 +32,21 @@ fn test_shared_lock() {
|
||||
shared z := &St{
|
||||
a: read_threads
|
||||
}
|
||||
for _ in 0..read_threads {
|
||||
for _ in 0 .. read_threads {
|
||||
go f(shared x, shared z)
|
||||
}
|
||||
for i in 0..writes {
|
||||
for i in 0 .. writes {
|
||||
lock x { // wait for ongoing reads to finish, don't start new ones
|
||||
x.a = 17 // this should never be read
|
||||
time.sleep_ms(50)
|
||||
x.a = if (i&1) == 0 { 7 } else { 5 }
|
||||
x.a = if (i & 1) == 0 { 7 } else { 5 }
|
||||
} // now new reads are possible again
|
||||
time.sleep_ms(20)
|
||||
}
|
||||
// wait until all read threads are finished
|
||||
for finished := false; ; {
|
||||
for finished := false; true; {
|
||||
mut rr := 0
|
||||
lock z {
|
||||
rlock z {
|
||||
rr = z.a
|
||||
finished = z.a == 0
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ mut:
|
||||
}
|
||||
|
||||
fn (shared x St) f(shared z St) {
|
||||
for _ in 0..reads_per_thread {
|
||||
for _ in 0 .. reads_per_thread {
|
||||
rlock x { // other instances may read at the same time
|
||||
time.sleep_ms(1)
|
||||
assert x.a == 7 || x.a == 5
|
||||
@ -20,8 +20,8 @@ fn (shared x St) f(shared z St) {
|
||||
|
||||
const (
|
||||
reads_per_thread = 30
|
||||
read_threads = 10
|
||||
writes = 5
|
||||
read_threads = 10
|
||||
writes = 5
|
||||
)
|
||||
|
||||
fn test_shared_lock() {
|
||||
@ -32,21 +32,21 @@ fn test_shared_lock() {
|
||||
shared z := &St{
|
||||
a: read_threads
|
||||
}
|
||||
for _ in 0..read_threads {
|
||||
for _ in 0 .. read_threads {
|
||||
go x.f(shared z)
|
||||
}
|
||||
for i in 0..writes {
|
||||
for i in 0 .. writes {
|
||||
lock x { // wait for ongoing reads to finish, don't start new ones
|
||||
x.a = 17 // this value should never be read
|
||||
time.sleep_ms(50)
|
||||
x.a = if (i&1) == 0 { 7 } else { 5 }
|
||||
x.a = if (i & 1) == 0 { 7 } else { 5 }
|
||||
} // now new reads are possible again
|
||||
time.sleep_ms(20)
|
||||
}
|
||||
// wait until all read threads are finished
|
||||
for finished := false; ; {
|
||||
for finished := false; true; {
|
||||
mut rr := 0
|
||||
lock z {
|
||||
rlock z {
|
||||
rr = z.a
|
||||
finished = z.a == 0
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ mut:
|
||||
}
|
||||
|
||||
fn f(shared x St, shared y St, shared z St) {
|
||||
for _ in 0..101 {
|
||||
for _ in 0 .. 101 {
|
||||
lock x, y {
|
||||
tmp := y.a
|
||||
y.a = x.a
|
||||
@ -30,7 +30,7 @@ fn test_shared_lock() {
|
||||
a: 1
|
||||
}
|
||||
go f(shared x, shared y, shared z)
|
||||
for _ in 0..100 {
|
||||
for _ in 0 .. 100 {
|
||||
lock x, y {
|
||||
tmp := x.a
|
||||
x.a = y.a
|
||||
@ -38,8 +38,8 @@ fn test_shared_lock() {
|
||||
}
|
||||
}
|
||||
// the following would be a good application for a channel
|
||||
for finished := false; ; {
|
||||
lock z {
|
||||
for finished := false; true; {
|
||||
rlock z {
|
||||
finished = z.a == 0
|
||||
}
|
||||
if finished {
|
||||
@ -47,7 +47,7 @@ fn test_shared_lock() {
|
||||
}
|
||||
time.sleep_ms(100)
|
||||
}
|
||||
lock x, y {
|
||||
rlock x, y {
|
||||
assert x.a == 7 && y.a == 5
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user