checker, cgen: implement auto-lock for `a[i]++`, `a[i]--` (#5817)
parent
b04fff272e
commit
6e6010d198
|
@ -404,6 +404,8 @@ pub:
|
|||
op token.Kind
|
||||
expr Expr
|
||||
pos token.Position
|
||||
pub mut:
|
||||
auto_locked string
|
||||
}
|
||||
|
||||
pub struct PrefixExpr {
|
||||
|
|
|
@ -2855,7 +2855,7 @@ fn (c Checker) has_return(stmts []ast.Stmt) ?bool {
|
|||
return none
|
||||
}
|
||||
|
||||
pub fn (mut c Checker) postfix_expr(node ast.PostfixExpr) table.Type {
|
||||
pub fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) table.Type {
|
||||
typ := c.expr(node.expr)
|
||||
typ_sym := c.table.get_type_symbol(typ)
|
||||
// if !typ.is_number() {
|
||||
|
@ -2864,7 +2864,7 @@ pub fn (mut c Checker) postfix_expr(node ast.PostfixExpr) table.Type {
|
|||
c.error('invalid operation: $node.op.str() (non-numeric type `$typ_sym.name`)',
|
||||
node.pos)
|
||||
} else {
|
||||
c.fail_if_immutable(node.expr)
|
||||
node.auto_locked, _ = c.fail_if_immutable(node.expr)
|
||||
}
|
||||
if (typ.is_ptr() || typ_sym.is_pointer()) && !c.inside_unsafe {
|
||||
c.error('pointer arithmetic is only allowed in `unsafe` blocks', node.pos)
|
||||
|
|
|
@ -1745,10 +1745,17 @@ fn (mut g Gen) expr(node ast.Expr) {
|
|||
g.write(')')
|
||||
}
|
||||
ast.PostfixExpr {
|
||||
if node.auto_locked != '' {
|
||||
g.writeln('sync__RwMutex_w_lock($node.auto_locked->mtx);')
|
||||
}
|
||||
g.inside_map_postfix = true
|
||||
g.expr(node.expr)
|
||||
g.inside_map_postfix = false
|
||||
g.write(node.op.str())
|
||||
if node.auto_locked != '' {
|
||||
g.writeln(';')
|
||||
g.write('sync__RwMutex_w_unlock($node.auto_locked->mtx)')
|
||||
}
|
||||
}
|
||||
ast.PrefixExpr {
|
||||
if node.op == .amp {
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
import sync
|
||||
import time
|
||||
|
||||
const (
|
||||
iterations_per_thread = 100000
|
||||
)
|
||||
|
||||
fn add_elements(shared foo []int, n int) {
|
||||
for _ in 0 .. iterations_per_thread {
|
||||
foo << n
|
||||
}
|
||||
foo[0]++
|
||||
}
|
||||
|
||||
fn test_autolocked_array() {
|
||||
shared abc := &[0]
|
||||
go add_elements(shared abc, 1)
|
||||
go add_elements(shared abc, 3)
|
||||
for _ in 0 .. iterations_per_thread {
|
||||
abc << 0
|
||||
}
|
||||
// wait for coroutines to finish - that should really be
|
||||
// done by channels, yield, semaphore...
|
||||
for {
|
||||
mut finished_threads := 0
|
||||
rlock abc {
|
||||
finished_threads = abc[0]
|
||||
}
|
||||
if finished_threads == 2 {
|
||||
break
|
||||
}
|
||||
time.sleep_ms(100)
|
||||
}
|
||||
// create histogram of results
|
||||
mut result := [0, 0, 0, 0]
|
||||
rlock abc {
|
||||
// automatic rlock for iteration is also not implemented, yet
|
||||
for v in abc {
|
||||
if v > 3 {
|
||||
panic('unexpected element on array')
|
||||
}
|
||||
result[v]++
|
||||
}
|
||||
}
|
||||
assert result[0] == iterations_per_thread
|
||||
assert result[1] == iterations_per_thread
|
||||
assert result[2] == 1 // number of non-main threads
|
||||
assert result[3] == iterations_per_thread
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
import sync
|
||||
import time
|
||||
|
||||
const (
|
||||
iterations_per_thread2 = 100000
|
||||
)
|
||||
|
||||
fn inc_elements(shared foo []int, n int) {
|
||||
for _ in 0 .. iterations_per_thread2 {
|
||||
foo[n]++
|
||||
}
|
||||
foo[0]++ // indicat that thread is finished
|
||||
}
|
||||
|
||||
fn test_autolocked_array_2() {
|
||||
shared abc := &[0, 0, 0]
|
||||
go inc_elements(shared abc, 1)
|
||||
go inc_elements(shared abc, 2)
|
||||
for _ in 0 .. iterations_per_thread2 {
|
||||
abc[2]++
|
||||
}
|
||||
// wait for coroutines to finish - that should really be
|
||||
// done by channels, yield, semaphore...
|
||||
for {
|
||||
mut finished_threads := 0
|
||||
rlock abc {
|
||||
finished_threads = abc[0]
|
||||
}
|
||||
if finished_threads == 2 {
|
||||
break
|
||||
}
|
||||
time.sleep_ms(100)
|
||||
}
|
||||
rlock abc {
|
||||
assert abc[1] == iterations_per_thread2
|
||||
assert abc[2] == 2 * iterations_per_thread2
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue