跳转至

多线程并发访问变量的安全控制语法

语法

  • with shared 变量名 => 局部变量 do 语句段
with shared a=>a do
    a:=100;

把多线程共享变量"a"映射到变量a,可以在with do的语句段中通过a访问共享变量。
这个时候会对该共享变量"a"加锁以确保安全。
  • with shared 变量名1 => 局部变量1, 变量名2 => 局部变量2 do 语句段
with shared a=>a, b=>b do begin
    println("a={}, b={}", a, b);
    b:=a;
    a:=array(1,2,3);
end;

最多支持同时安全访问2个共享变量。

嵌套with shared语句的支持

可以嵌套,但是只保护当前with shared定义的变量(为了避免可能因加锁次序而导致的死锁问题)。 所以在这样的情况下,不要使用上一层定义的共享变量。

with shared a=>a do
begin
    a:=100;
    with shared b=>b do
    begin
        // 在这里不要使用a
        b:=200;
        println("b={}", b); 
    end
    // 这时可以安全使用a
    println("a={}", a);
end

样例

例子

// 初始化共享变量a
with shared a=>a do 
    a:=100;

// 启动线程1    
taskgroup_run(tg, () => 
begin
    res := 0;
    for i:=0 to 1000 do 
    begin
        sleep(1);
        with shared a=>a do 
        begin
            println("thread1: before a={}", a); 
            a++;
            println("thread1: after  a={}", a); 
            res := a;
        end
    end     
    println("thread1 exit, return {}", res);    
    return res;
end);

// 启动线程2
taskgroup_run(tg, () => 
begin
    res := 0;
    for i:=0 to 2000 do 
    begin
        sleep(1);
        with shared a=>a do 
        begin
                println("thread2: before a={}", a); 
                a--;
                println("thread2: after  a={}", a); 
                res := a;
        end
    end
    println("thread2 exit, return {}", res);    
    return res;
end);

// 等待所有任务结束
res := taskgroup_wait_all(tg);
println("res={}", res);
taskgroup_destroy(tg);

运行打印:

thread2: before a=100
thread2: after  a=99
thread1: before a=99
thread1: after  a=100
thread2: before a=100
thread2: after  a=99
thread1: before a=99
thread1: after  a=100
thread1: before a=100
thread1: after  a=101
thread2: before a=101
thread2: after  a=100
thread2: before a=100
thread2: after  a=99
thread1: before a=99
thread1: after  a=100
thread2: before a=100
thread2: after  a=99
...

避免死锁

tg := taskgroup_create(5);

// 线程1 访问次序是先"a"后"b"
taskgroup_run(tg, () => 
begin
    for i:=0 to 10000 do 
    begin
        sleep(1);
        with shared a=>a do 
        begin
            a:=i;
            println("thread1: a={}", a);
            with shared b=>b do
            begin
                b:=i-1;
                println("thread1: b={}", b);
            end
        end
    end 
end);

// 线程2 访问次序是先"b"后"a"
taskgroup_run(tg, () => 
begin
    for i:=10000 to 20000 do 
    begin
        sleep(1);
        with shared b=>b do 
        begin
            b:=i;
            println("thread2: b={}", b);
            with shared a=>a do
            begin
                a:=i-1;
                println("thread2: a={}", a);
            end
        end
    end 
end);

res := taskgroup_wait_all(tg);
println("res={}", res);
taskgroup_destroy(tg);

打印:

thread1: a=0
thread2: b=10000
thread2: a=9999
thread1: b=-1
thread2: b=10001
thread1: a=1
thread1: b=0
thread2: a=10000
thread2: b=10002
thread1: a=2
thread1: b=1
thread2: a=10001
thread1: a=3
thread2: b=10003
thread2: a=10002
thread1: b=2
thread2: b=10004
...

虽然共享变量的访问次序不同,但是并没有发生死锁。