This post is not yet complete.

This is Part 2 in my Multithreading in Perl 6 series. This assumes you have read Part 1.

Concurrency and Thinking with Threads

While Perl 6 makes it very easy to work do asynchronous work with multiple threads, there are things you need to keep in mind. Let's see a simple example of where threading can go terribly wrong!

my $i = 0;
await do for ^10000 {
    start {
        $i++;
    }
}
say $i;
# 9971
# Result is not consistent on different runs of the program

Hmm.. we told it to iterate 10,000 times, but we did not get a total of 10,000 by the end. What went wrong? When you iterate a variable with $i++ Perl 6 gets the value of $i, adds one to it, and sets $i to that value. If two threads read the variable at the same time and read the value as 150 they then each add one to 150 and then set $i to 151.

You should never be writing to global variables when using threading. Just don't do it!

Let's see how we can safely do this. One very easy way is to use the return values from the threads. The object returned by the last statement is what is returned.

my @result = await do for ^10000 {
    start {
        1;
    }
}
say @result.sum;
# 10000

You could also use Channels or Supplies to do this if you needed to share information between threads.

Locks

It is best practice to not manually use Lock. Despite this, knowing how Lock works will help you better understand other Perl 6 concepts which use Locks under the hood. We create a lock with Lock.new. We can then call the .protect method on that lock to protect a section of code inside that lock. Any code protected by the same Lock object will never be running in two threads at once.

my $lock = Lock.new;
my $j = 0;
await do for ^10000 {
    start {
        $lock.protect( {
            $j++;
        } );
    }
}
say $j;
# 10000

The main issue with Lock is that any code protected will block execution until the Lock is unlocked when another protect section is done.

Supplies

In Part 1 we used the react block to react to things specified by whenever. Under the hood react works using Supplies.

There are two kinds of Supplies, live and on-demand Supplies. Live Supplies will only receive messages from the time in which they tap into the Supply. A Supplier will emit messages and anything subscribed to it will receive them. We use Supplier.new to create a live Supplier, and .Supply to get a Supply we can tap into.

# Supplier.new creates a `live` Supplier
my $supplier = Supplier.new;
my $supply   = $supplier.Supply;
say "Is Supply live? {$supply.live}";
$supply.tap( -> $v { say $v });
for 1 .. 10 {
    $supplier.emit($_);
}

.tap is not guarenteed to be executed in only one thread at a time. So make sure to not write to any shared variables. Remember react from before? React uses .act, which is similar to .tap but is guarenteed to only execute in one thread at a time.