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 {
|
if g.is_assign_lhs && !is_selector && node.is_setter {
|
||||||
g.is_array_set = true
|
g.is_array_set = true
|
||||||
g.write('array_set(')
|
g.write('array_set(')
|
||||||
if !left_is_ptr {
|
if !left_is_ptr || node.left_type.has_flag(.shared_f) {
|
||||||
g.write('&')
|
g.write('&')
|
||||||
}
|
}
|
||||||
g.expr(node.left)
|
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.write(', ')
|
||||||
g.expr(node.index)
|
g.expr(node.index)
|
||||||
mut need_wrapper := true
|
mut need_wrapper := true
|
||||||
@ -2404,10 +2411,17 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
|
|||||||
info.elem_type != table.string_type {
|
info.elem_type != table.string_type {
|
||||||
// TODO move this
|
// TODO move this
|
||||||
g.write('*($elem_type_str*)array_get(')
|
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.write('*')
|
||||||
}
|
}
|
||||||
g.expr(node.left)
|
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.write(', ')
|
||||||
g.expr(node.index)
|
g.expr(node.index)
|
||||||
g.write(') ')
|
g.write(') ')
|
||||||
@ -2428,10 +2442,17 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
g.write('(*($elem_type_str*)array_get(')
|
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.write('*')
|
||||||
}
|
}
|
||||||
g.expr(node.left)
|
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.write(', ')
|
||||||
g.expr(node.index)
|
g.expr(node.index)
|
||||||
g.write('))')
|
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) {
|
fn (mut g Gen) array_init(it ast.ArrayInit) {
|
||||||
type_sym := g.table.get_type_symbol(it.typ)
|
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 {
|
if type_sym.kind == .array_fixed {
|
||||||
g.write('{')
|
g.write('{')
|
||||||
for i, expr in it.exprs {
|
for i, expr in it.exprs {
|
||||||
@ -4568,6 +4607,14 @@ fn (mut g Gen) array_init(it ast.ArrayInit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.write('}))')
|
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)` =>
|
// `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) {
|
fn (shared x St) f(shared y St, shared z St) {
|
||||||
for _ in 0..101 {
|
for _ in 0 .. 101 {
|
||||||
lock x, y {
|
lock x, y {
|
||||||
tmp := y.a
|
tmp := y.a
|
||||||
y.a = x.a
|
y.a = x.a
|
||||||
@ -30,7 +30,7 @@ fn test_shared_receiver_lock() {
|
|||||||
a: 1
|
a: 1
|
||||||
}
|
}
|
||||||
go x.f(shared y, shared z)
|
go x.f(shared y, shared z)
|
||||||
for _ in 0..100 {
|
for _ in 0 .. 100 {
|
||||||
lock x, y {
|
lock x, y {
|
||||||
tmp := x.a
|
tmp := x.a
|
||||||
x.a = y.a
|
x.a = y.a
|
||||||
@ -38,8 +38,8 @@ fn test_shared_receiver_lock() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// the following would be a good application for a channel
|
// the following would be a good application for a channel
|
||||||
for finished := false; ; {
|
for finished := false; true; {
|
||||||
lock z {
|
rlock z {
|
||||||
finished = z.a == 0
|
finished = z.a == 0
|
||||||
}
|
}
|
||||||
if finished {
|
if finished {
|
||||||
@ -47,7 +47,7 @@ fn test_shared_receiver_lock() {
|
|||||||
}
|
}
|
||||||
time.sleep_ms(100)
|
time.sleep_ms(100)
|
||||||
}
|
}
|
||||||
lock x, y {
|
rlock x, y {
|
||||||
assert x.a == 7 && y.a == 5
|
assert x.a == 7 && y.a == 5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ mut:
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn f(shared x St, shared z St) {
|
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
|
rlock x { // other instances may read at the same time
|
||||||
time.sleep_ms(1)
|
time.sleep_ms(1)
|
||||||
assert x.a == 7 || x.a == 5
|
assert x.a == 7 || x.a == 5
|
||||||
@ -32,21 +32,21 @@ fn test_shared_lock() {
|
|||||||
shared z := &St{
|
shared z := &St{
|
||||||
a: read_threads
|
a: read_threads
|
||||||
}
|
}
|
||||||
for _ in 0..read_threads {
|
for _ in 0 .. read_threads {
|
||||||
go f(shared x, shared z)
|
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
|
lock x { // wait for ongoing reads to finish, don't start new ones
|
||||||
x.a = 17 // this should never be read
|
x.a = 17 // this should never be read
|
||||||
time.sleep_ms(50)
|
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
|
} // now new reads are possible again
|
||||||
time.sleep_ms(20)
|
time.sleep_ms(20)
|
||||||
}
|
}
|
||||||
// wait until all read threads are finished
|
// wait until all read threads are finished
|
||||||
for finished := false; ; {
|
for finished := false; true; {
|
||||||
mut rr := 0
|
mut rr := 0
|
||||||
lock z {
|
rlock z {
|
||||||
rr = z.a
|
rr = z.a
|
||||||
finished = z.a == 0
|
finished = z.a == 0
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ mut:
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn (shared x St) f(shared z St) {
|
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
|
rlock x { // other instances may read at the same time
|
||||||
time.sleep_ms(1)
|
time.sleep_ms(1)
|
||||||
assert x.a == 7 || x.a == 5
|
assert x.a == 7 || x.a == 5
|
||||||
@ -32,21 +32,21 @@ fn test_shared_lock() {
|
|||||||
shared z := &St{
|
shared z := &St{
|
||||||
a: read_threads
|
a: read_threads
|
||||||
}
|
}
|
||||||
for _ in 0..read_threads {
|
for _ in 0 .. read_threads {
|
||||||
go x.f(shared z)
|
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
|
lock x { // wait for ongoing reads to finish, don't start new ones
|
||||||
x.a = 17 // this value should never be read
|
x.a = 17 // this value should never be read
|
||||||
time.sleep_ms(50)
|
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
|
} // now new reads are possible again
|
||||||
time.sleep_ms(20)
|
time.sleep_ms(20)
|
||||||
}
|
}
|
||||||
// wait until all read threads are finished
|
// wait until all read threads are finished
|
||||||
for finished := false; ; {
|
for finished := false; true; {
|
||||||
mut rr := 0
|
mut rr := 0
|
||||||
lock z {
|
rlock z {
|
||||||
rr = z.a
|
rr = z.a
|
||||||
finished = z.a == 0
|
finished = z.a == 0
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ mut:
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn f(shared x St, shared y St, shared z St) {
|
fn f(shared x St, shared y St, shared z St) {
|
||||||
for _ in 0..101 {
|
for _ in 0 .. 101 {
|
||||||
lock x, y {
|
lock x, y {
|
||||||
tmp := y.a
|
tmp := y.a
|
||||||
y.a = x.a
|
y.a = x.a
|
||||||
@ -30,7 +30,7 @@ fn test_shared_lock() {
|
|||||||
a: 1
|
a: 1
|
||||||
}
|
}
|
||||||
go f(shared x, shared y, shared z)
|
go f(shared x, shared y, shared z)
|
||||||
for _ in 0..100 {
|
for _ in 0 .. 100 {
|
||||||
lock x, y {
|
lock x, y {
|
||||||
tmp := x.a
|
tmp := x.a
|
||||||
x.a = y.a
|
x.a = y.a
|
||||||
@ -38,8 +38,8 @@ fn test_shared_lock() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// the following would be a good application for a channel
|
// the following would be a good application for a channel
|
||||||
for finished := false; ; {
|
for finished := false; true; {
|
||||||
lock z {
|
rlock z {
|
||||||
finished = z.a == 0
|
finished = z.a == 0
|
||||||
}
|
}
|
||||||
if finished {
|
if finished {
|
||||||
@ -47,7 +47,7 @@ fn test_shared_lock() {
|
|||||||
}
|
}
|
||||||
time.sleep_ms(100)
|
time.sleep_ms(100)
|
||||||
}
|
}
|
||||||
lock x, y {
|
rlock x, y {
|
||||||
assert x.a == 7 && y.a == 5
|
assert x.a == 7 && y.a == 5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user