Asynchronous Locking
 
        
        
    Raku actually provides two different locking classes. A
Lock object provides a very standard
locking mechanism. When .lock and .unlock are used or .protect is called,
you get a section of code that pauses until the lock frees up, runs while
holding the lock, and then frees the lock so other code that might be waiting on
the lock can run.
However, the Lock class works in such a way that blocks the current thread. As
I’ve pointed out earlier in this advent calendar, the purpose of threads is to
do stuff, so blocking them from running is preventing them from fulfilling their
purpose. Luckily, there is a solution.
In cases where you want locking, but don’t want to burn your threads waiting for
the lock to free up, consider using
Lock::Async instead of Lock. It
works very similarly to Lock, but the .lock method does not block. Instead,
it returns a Promise which will be kept
when the lock is free.  Code that awaits that Promise will pause in a way
that allows Raku to reuse the current thread for another task:
class SafeQueue {
    has @!queue;
    has Lock::Async $!lock .= new;
    method enqueue($value) {
        await $!lock.lock;
        push @!queue, $value;
        $!lock.unlock;
    }
    method dequeue(--> Any) {
        $!lock.protect: { shift @!queue }
    }
}
The code above demonstrates both the use of .lock and .unlock as well as
.protect. You should always prefer .protect as the code in enqueue above
might leave the lock forever held if an exception gets thrown after the lock is
acquired. From the point of view of your program, a .protect will behave
similarly between Lock and Lock::Async, but internally performs an await
on the .lock method. This means that the thread the code is running on will be
freed to be used by another task that is waiting to be scheduled.
Cheers.
