How to prevent a race condition in moose with lazy attributes and Coro

The project we are working on uses Coro for asynchronous processing, and, unfortunately, it is too large to move away from Coro in the near future. We are faced with a race condition, when an object with a lazy attribute calls the constructor for this lazy attribute inside the builder, for some reason the thread yields, and then another coro thread tries to access the same attribute that starts the attribute that will be created again.

Normally, I would protect the check and then set the code using a semaphore, however, checking and establishing Moose behavior inside the moose, not my own code.

How can I remove this race condition?

+4
source share
1 answer

Usually you control access to an object or attribute from the outside.

my $foo_bar_lock = Coro::Semaphore->new();
my $foo = Foo->new();

{
   my $guard = $foo_bar_lock->guard;
   # ... use $foo bar ...
}

{
   my $guard = $foo_bar_lock->guard;
   # ... use $foo bar ...
}

But it can also be done from the inside out.

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(@_);
} 

(If you prefer to use only one get-set accessor instead of separate get and set accessors, use accessorinstead of readerand writer.)

+7
source

Source: https://habr.com/ru/post/1685000/


All Articles