class Lock::ConditionVariable {}

条件变量在 Lock 中用于等待特定条件变为真。您通常不会从头开始创建一个条件变量,而是调用 Lock.condition 在特定 Lock 上获取一个条件变量。

方法§

方法 wait§

multi method wait--> Nil )
multi method wait&predicate --> Nil )

如果没有谓词,它将等待条件变量本身;如果有谓词,则等待代码返回真值。

    my $times = 100;
    my $tried;
    my $failed;
    for ^$times {
        my $l = Lock.new;
        my $c = $l.condition;
        my $now1;
        my $now2;
        my $counter = 0;
        my $t1 = Thread.start({
            $l.protect({
                $c.wait{ $counter != 0 } );
                $now1 = now;
            });
        });
 
        my $t2 = Thread.start({
            $l.protect({
                $counter++;
                $c.signal();
            });
        });
 
        $t1.join();
        $now2 = now;
        $t2.join();
 
        $tried++;
        last if $failed = ( !$now1.defined or $now1 > $now2 );
    }

我们从 $l 锁获取的条件使用谓词等待,在本例中,检查计数器是否仍然为零。当它采用另一个值时,程序流继续执行下一条指令。

方法 signal§

method signal()

当且仅当有任何线程先前已等待条件变量时,它将解除其中至少一个线程的阻塞。让我们看看它在这个示例中的工作原理

constant ITEMS = 100;
for 1..15 -> $iter {
    my $lock = Lock.new;
    my $cond = $lock.condition;
    my $todo = 0;
    my $done = 0;
    my @in = 1..ITEMS;
    my @out = 0 xx ITEMS;
 
    for 1..ITEMS -> $i {
        my $in = $i;
        my $out := @out[$i];
        Thread.start{
                    $out = $in * 10;
                    $lock.protect{
                        $done++;
                        $cond.signal if $done == $todo;
                    } );
        } );
        $todo++;
    }
    $lock.protect{
        $cond.wait({  $done == $todo } );
    });
    say @out;
}

我们重复 15 次相同的操作:启动 100 个线程,每个线程修改数组中的单个元素。我们protect全局变量 $done 的修改,并使用 signal 唤醒另一个线程来执行其操作。这将输出生成数组的前几个元素。