如何使用 Lazy 属性和 Coro 防止 Moose 中的竞争条件
How to prevent race condition in Moose with Lazy attributes and Coro
我们正在进行的项目使用 Coro 进行异步处理,不幸的是,它太大了,无法在不久的将来离开 Coro。我们 运行 进入了一种竞争条件,其中具有惰性属性的对象调用构建器中的构建器以获取线程出于某种原因放弃的该惰性属性,然后另一个 coro 线程尝试访问相同的属性,从而触发该属性重新建造。
通常我会保护检查然后使用信号量设置代码,但是 Moose 的检查和设置行为在 moose 内部而不是我自己的代码。
我怎样才能消除这个竞争条件?
通常,您会控制从外部访问对象或属性。
my $foo_bar_lock = Coro::Semaphore->new();
my $foo = Foo->new();
{
my $guard = $foo_bar_lock->guard;
# ... use $foo's bar ...
}
{
my $guard = $foo_bar_lock->guard;
# ... use $foo's bar ...
}
但是,它也可以从内部完成。
has bar_lock => (
reader => '_get_bar_lock',
default => sub { Coro::Semaphore->new() },
);
has bar => (
reader => '_get_bar',
writer => '_set_bar',
builder => '_build_bar',
lazy => 1,
);
sub _build_bar { ... }
sub get_bar {
my $self = shift;
my $guard = $self->_get_bar_lock->guard;
return $self->_get_bar();
}
sub set_bar {
my $self = shift;
my $guard = $self->_get_bar_lock->guard;
return $self->_set_bar(@_);
}
(如果您更喜欢单个 get-set 访问器而不是单独的 get 和 set 访问器,请使用 accessor
而不是 reader
和 writer
。)
我们正在进行的项目使用 Coro 进行异步处理,不幸的是,它太大了,无法在不久的将来离开 Coro。我们 运行 进入了一种竞争条件,其中具有惰性属性的对象调用构建器中的构建器以获取线程出于某种原因放弃的该惰性属性,然后另一个 coro 线程尝试访问相同的属性,从而触发该属性重新建造。
通常我会保护检查然后使用信号量设置代码,但是 Moose 的检查和设置行为在 moose 内部而不是我自己的代码。
我怎样才能消除这个竞争条件?
通常,您会控制从外部访问对象或属性。
my $foo_bar_lock = Coro::Semaphore->new();
my $foo = Foo->new();
{
my $guard = $foo_bar_lock->guard;
# ... use $foo's bar ...
}
{
my $guard = $foo_bar_lock->guard;
# ... use $foo's bar ...
}
但是,它也可以从内部完成。
has bar_lock => (
reader => '_get_bar_lock',
default => sub { Coro::Semaphore->new() },
);
has bar => (
reader => '_get_bar',
writer => '_set_bar',
builder => '_build_bar',
lazy => 1,
);
sub _build_bar { ... }
sub get_bar {
my $self = shift;
my $guard = $self->_get_bar_lock->guard;
return $self->_get_bar();
}
sub set_bar {
my $self = shift;
my $guard = $self->_get_bar_lock->guard;
return $self->_set_bar(@_);
}
(如果您更喜欢单个 get-set 访问器而不是单独的 get 和 set 访问器,请使用 accessor
而不是 reader
和 writer
。)