1
0
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:
Uwe Krüger 2020-07-08 11:05:43 +02:00 committed by GitHub
parent 38000f8622
commit 88248b1b66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 117 additions and 29 deletions

View File

@ -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)` =>

View 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
}
}

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}
}