N. B. The examples below require a fresh Rakudo compiler, at least of the version 2017.09.
Discussing parallel computing earlier or later leads to solving race conditions. Let us look at a simple counter that is incremented by two parallel threads:
my $c = 0; await do for 1..10 { start { $c++ for 1 .. 1_000_000 } } say $c;
If you run the program a few times, you will immediately see that the results are very different:
$ perl6 atomic-1.pl 3141187 $ perl6 atomic-1.pl 3211980 $ perl6 atomic-1.pl 3174944 $ perl6 atomic-1.pl 3271573
Of course, the idea was to increase the counter by 1 million in all of the ten threads, but about ⅓ of the steps were lost. It is quite easy to understand why that happens: the parallel threads read the variable and write to it ignoring the presence of other threads and not thinking that the value can be changed in-between. Thus, some of the threads work with an outdated value of the counter.
Perl 6 offers a solution: atomic operations. The syntax of the language is equipped with the Atom Symbol (U+0x269B) ⚛ character (no idea of why it is displayed in that purple colour). Instead of $c++, you should type $c⚛++.
my atomicint $c = 0; await do for 1..10 { start { $câš›++ for 1 .. 1_000_000 } } say $c;
And before thinking of the necessity to use a Unicode character, let us look at the result of the updated program:
$ perl6 atomic-2.pl 10000000
This is exactly the result we wanted!
Notice also, that the variable is declared as a variable of the atomicint type. That is a synonym for int, which is a native integer (unlike Int, which is a data type represented by a Perl 6 class).
It is not possible to ask a regular value to be atomic. That attempt will be rejected by the compiler:
$ perl6 -e'my $c; $câš›++' Expected a modifiable native int argument for '$target' in block at -e line 1
A few other operators can be atomic, for example, prefix and postfix increments and decrements ++ and --, or += and -=. There are also atomic versions of the assignment operator = and the one for reading: ⚛ (sic!).
If you need atomic operations in your code, you are not forced to use the ⚛ character. There exists a bunch of alternative functions that you can use instead of the operators:
my atomicint $c = 1; my $x = âš›$c; $x = atomic-fetch($c); $c âš›= $x; atomic-assign($c, $x); $câš›++; atomic-fetch-inc($c); $câš›--; atomic-fetch-dec($c); ++âš›$c; atomic-inc-fetch($c); --âš›$c; atomic-dec-fetch($c); $c âš›+= $x; atomic-fetch-add($c,$x); say $x; # 1 say $c; # 3
2 thoughts on “🦋 66. Atomic operations in Perl 6”