Acme-Parataxis
view release on metacpan or search on metacpan
lib/Acme/Parataxis/Sync/RwLock.pod view on Meta::CPAN
# read-protected scope
}
Acquires a read hold via C<read_lock()> and returns an opaque guard object. When the guard goes out of scope (or is
unwound by an exception), it invokes C<read_unlock()> automatically.
=head2 C<write_guard( )>
{
my $guard = $lock->write_guard;
# write-protected scope
}
Acquires the exclusive write lock via C<write_lock()> and returns an opaque guard object. When the guard is destroyed,
it invokes C<write_unlock()> automatically.
=head2 C<readers( )>
Returns the total count of outstanding read holds across all fibers (including deepened holds).
=head2 C<read_holders( )>
Returns the count of distinct I<fibers> currently holding at least one read hold.
=head2 C<writer( )> / C<owner( )>
Returns the numeric fiber ID of the current exclusive writer, or C<undef> if not write-held. C<owner> is an alias.
=head2 C<waiters( )>
Returns the total number of fibers currently parked waiting for either read or write access.
=head2 C<read_waiters( )> / C<write_waiters( )>
In scalar context, returns the count of fibers waiting for read or write access, respectively. In list context, returns
their numeric fiber IDs. B<Wrap in C<scalar()> when interpolating into strings>:
say "Queued readers: " . scalar($lock->read_waiters);
=head1 Recipes
=head2 Nested read calls inside helpers
my $rwlock = Acme::Parataxis::Sync::RwLock->new;
sub fetch_field ($key) {
my $guard = $rwlock->read_guard; # deepens existing hold safely
return $data{$key};
}
async {
my $outer_guard = $rwlock->read_guard;
my $val1 = fetch_field('name');
my $val2 = fetch_field('role');
};
=head2 Deadlock prevention during writes
Because upgrading a read hold to a write hold is forbidden, release read holds before requesting a write lock:
sub update_record ($id, $new_val) {
# Check current value under read lock:
my $needs_update = 0;
{
my $guard = $rwlock->read_guard;
$needs_update = 1 if $data{$id} ne $new_val;
}
# Drop read hold before requesting write lock:
if ($needs_update) {
my $guard = $rwlock->write_guard;
$data{$id} = $new_val;
}
}
=head1 Behavior Notes
=over
=item * Upgrades from read to write are forbidden
Attempting to call C<write_lock()> while holding a read hold croaks with C<RwLock write_lock: this fiber holds a read
lock; upgrading read to write is not supported>. Upgrading cannot be supported safely without risking deadlocks when
multiple readers attempt to upgrade concurrently. Release the read hold first.
=item * Stranded holds brick the lock
If a fiber exits without unlocking (or without dropping a guard), its holds remain registered permanently. For write
holds, this blocks all future access. For read holds, recycled fiber IDs can cause a newer fiber with the same ID to be
falsely identified as holding a read hold. Always use guards.
=back
=head1 SEE ALSO
L<Acme::Parataxis::Sync>, L<Acme::Parataxis::Sync::Mutex>, L<Acme::Parataxis::Sync::WaitGroup>
=head1 AUTHOR
Sanko Robinson L<https://github.com/sanko>
=head1 LICENSE
Copyright (C) Sanko Robinson.
This library is free software; you can redistribute it and/or modify it under the terms found in the Artistic License
2.
=cut
( run in 0.647 second using v1.01-cache-2.11-cpan-145b269f2f3 )