锁.保护和召唤



我试图自动编写一个trait来threadsafe一个sub。这是我得到的:

#| A trait to ensure that a sub is not run on multiple threads simultaneously.
multi sub trait_mod:<is> (Sub code, :$protected!) {
# If :!protected, do nothing.
if $protected {
# Create a new lock outside the multithreaded area
my $lock = Lock.new;
# Wrap the sub with a routine that hides callsame in a lock
code.wrap: sub (|) {
$lock.protect: {callsame}
}
}
}
#| Should print "Start X and finish X" if properly protected
sub needs-protection($x) is protected {
print "Start $x and ";
sleep 1;
say "finish $x";
}
# Test it out.
# If not protected, completes in 1 second with malformed output
(1..4).hyper(:1batch, :4degree) { 
needs-protection $_
}

然而,AFAICT,似乎callsame没有做任何事情(它返回Nil,但就是这样)。我的猜测是,它以某种方式试图调用.protect的不同候选,但我没有看到一种方法来确保callsame链接到包装的子,而不是其他方法。

我可以通过

让它工作
multi sub trait_mod:<is> (Sub code, :$protected!) {
if $protected {
my $lock = Lock.new;
code.wrap: sub (|c) {
if CALLERS::<$*PROTECTED> {
$*PROTECTED = False;
return callsame;
}
$lock.protect: { 
my $*PROTECTED = True;
code.CALL-ME(|c);
}
}
}
}

但是感觉很模糊,我可能错过了一些东西,允许$*PROTECTEDTrue值在事情不安全时滑落。有没有一种方法可以在protect-ed块内部直接创建callsame?

callsame这样的延迟例程查找最近的动态作用域调度来恢复。传递给方法protect的块{callsame}将被protect方法调用,动态范围内最近的调度将是对protect的方法调度。因此,它将尝试遵从Lock基类中的protect方法。没有,因此Nil的结果。

要解决这个问题,我们需要在正确的动态范围内获得包装后的目标,并使其在词法上可用。这可以使用nextcallee:

实现
#| A trait to ensure that a sub is not run on multiple threads simultaneously.
multi sub trait_mod:<is> (Sub code, :$protected!) {
# If :!protected, do nothing.
if $protected {
# Create a new lock outside the multithreaded area
my $lock = Lock.new;
# Wrap the sub with a routine that hides callsame in a lock
code.wrap: sub (|c) {
my &target = nextcallee;
$lock.protect: { target(|c) }
}
}
}
#| Should print "Start X and finish X" if properly protected
sub needs-protection($x) is protected {
print "Start $x and ";
sleep 1;
say "finish $x";
}
# Test it out.
# If not protected, completes in 1 second with malformed output
for (1..4).hyper(:1batch, :4degree) { 
needs-protection $_
}

这给出了我期望你所期望的输出。

最新更新