Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent race condition in Moose with Lazy attributes and Coro

Tags:

perl

moose

The project we are working on makes use of the Coro for asynchronous processing and unfortunately it is too large to move away from Coro in the near future. We are running into a race condition where an object with a lazy attribute calls the builder for that lazy attribute inside the builder the thread cedes for some reason and then a different coro thread attempts to access the same attribute triggering the attribute to be built again.

Normally I would protect the check and then set code with a semaphore however the check and set behaviour of Moose is inside of moose rather then my own code.

How can I remove this race condition?

like image 361
Q the Platypus Avatar asked Mar 08 '23 04:03

Q the Platypus


1 Answers

Normally, you'd control access to the 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's bar ...
}

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

But, it can be done from the inside too.

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 a single get-set accessor instead of separate get and set accessors, use accessor instead of reader and writer.)

like image 96
ikegami Avatar answered May 16 '23 07:05

ikegami