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 )