1Perl6::Bible::S17(3) User Contributed Perl Documentation Perl6::Bible::S17(3)
2
3
4
6 Synopsis_17 - Concurrency [DRAFT]
7
9 Elizabeth Mattijsen <liz@dijkmat.nl>
10 Audrey Tang <autrijus@autrijus.org>
11
13 Maintainer: Elizabeth Mattijsen <liz@dijkmat.nl>
14 Date: 13 Jun 2005
15 Last Modified: 13 Nov 2005
16 Number: 0
17 Version: 1
18
20 This is a rough sketch of how concurrency works in Perl 6.
21
22 (actually these are just random notes, put here under the release-early
23 release-often principle, slowly being integrated in a more textual
24 format. Patches welcome!)
25
27 Concurrency can take many forms in Perl 6. With varying degrees of
28 explicitness and control capabilities. This document attempts to
29 describe what these capabilities are and in which form they can be
30 accessed in Perl 6.
31
32 Processes, threads, fibers?
33 Concurrency comes in many shapes and forms. Most Perl users are used
34 to the concept of a "process" or a "thread" (usually depending on the
35 OS they work on). Some systems even are familiar with very lightweight
36 threads called "fibers".
37
38 When discussing issues about concurrency with different people, it soon
39 becomes apparent that everybody has his own set of "understandings"
40 about what each word means, which doesn't make it any easier to
41 describe Perl 6 concurrency.
42
43 It seemed the most natural to use the word "thread" to describe a
44 process which has its own context, but also shares context with 0 or
45 more concurrently running processes. Depending on your OS, or even
46 specific version of your OS, this could still be a single "process"
47 from the OS's point of view. Or it could contain an OS process for
48 each thread. Or any mixture of these two implementations.
49
50 In this document we try to be agnostic about this: all we know in Perl
51 6 are "threads", which have their own context and share context with
52 other concurrently running "threads". Whether they be process, threads
53 or fibres at the OS level should not matter at the Perl 6 level.
54
55 And for sake of consistency, an unthreaded "normal" program is
56 considered to be also running in a single thread.
57
58 Variables
59 In the past, there have been two models for concurrent processes in
60 Perl. In general, these are referred to as "5.005 threads" ("perldoc
61 perlothrtut") and "ithreads" ("perldoc perlthrtut").
62
63 The main difference between these two models from a programmer's point
64 of view, is that variables in "5.005 threads" are shared by default.
65 Whereas in the "ithreads" model, only variables that have been
66 indicated to be "shared", are actually shared between threads. All
67 other variable values are actually copies of the variable's value in
68 the "parent" thread.
69
70 With regards to variables, the concurrency model of Perl 6 is closer to
71 the "5.005 threads" model than it is to the "ithreads" model. In fact,
72 all variables "visible" to a particular scope in Perl 6 will be
73 accessible and modifiable from all of the concurrent processes that
74 start from that scope. In that sense, one could consider the
75 "ithreads" model as a historical diversion: the Perl 6 concurrency
76 picks up where the "5.005 threads" path left off.
77
78 (EM: maybe point out that the "ithreads" behaviour can be simulated
79 with some kind of copy-on-write magic to be automagically added to all
80 variable access inside a thread, except for those with an explicit "is
81 shared" attribute?)
82
83 No user accessible locks
84 Differently from any current concurrent process implementation in Perl,
85 there are no user accessible locks. Instead, the concept of Software
86 Transactionable Memory is used. This is in concept similar to the use
87 of
88
89 BEGIN TRANSACTION
90 ... do your uninterruptible actions
91 COMMIT
92
93 in the database world. More interestingly, this also includes the
94 concept of rollback:
95
96 BEGIN TRANSACTION
97 ... do your stuff, but impossible to complete: ROLLBACK
98
99 This causes the state of the process to be reverted to the state at the
100 moment the BEGIN TRANSACTION was executed.
101
102 Perl 6 supports this concept through Code blocks which are marked "is
103 atomic". These sections are guaranteed to either be completed totally
104 (when the Code block is exited), or have their state reverted to the
105 state at the start of the Code block (with the retry statement).
106
107 (EM: maybe point out if / how old style locks can be "simulated", for
108 those needing a migration path?)
109
110 Atomic Code blocks
111 my ($x, $y);
112 sub c is atomic {
113 $x -= 3;
114 $y += 3;
115 if $x < 10 { retry }
116 };
117
118 $e = &c.retry_with( &d ); #
119 $e();
120
121 if $i { is atomic; ... } else { ...; }
122
123 A Code block can be marked as "is atomic". This means that code
124 executed inside that scope is guaranteed not to be interrupted in any
125 way.
126
127 The start of a block marked "is atomic" also becomes a "checkpoint" to
128 which execution can return (in exactly the same state) if a problem
129 occurs (a.k.a. a retry is done) inside the scope of the Code block.
130
131 retry
132
133 The "retry" function basically restores the state of the thread at the
134 last checkpoint and will wait there until an external event allows it
135 to potentially run that atomic section of code again without having to
136 retry again.
137
138 If there are no external events possible that could restart execution,
139 an exception will be raised.
140
141 The last checkpoint is either the last atomic / non-atomic boundary, or
142 the most immediate caller constructed with "retry_with".
143
144 retry_with
145
146 The "retry_with" method on an atomic Code object causes a checkpoint to
147 be made for "retry", creating an alternate execution path to be
148 followed when a "retry" is done.
149
150 limitations
151
152 Because Perl 6 must be able to revert its state to the state it had at
153 the checkpoint, it is not allowed to perform any non-revertable
154 actions. These would include reading / writing from file handles that
155 do not support "seek" (such as sockets). Attempting to do so will
156 cause a fatal error to occur.
157
158 If you're not interested in revertability, but are interested in
159 uninteruptability, you could use the "is critical" trait.
160
161 Critical Code blocks
162 sub tricky is critical {
163 # code accessing external info, not to be interrupted
164 }
165
166 if ($update) {
167 is critical;
168 # code accessing external info, not to be interrupted
169 }
170
171 A Code block marked "is critical" can not be interrupted in any way.
172 But since it is able to access non-revertible data structures (such as
173 non-seekable file handles), it cannot do a "retry" as it would be
174 impossible to restore the state to the beginning of the Code block.
175
176 Mixing Atomic and Critical
177 Both "atomic" as well as "critical" propagate down the call chain.
178 This means that any subroutine that in itself is not "atomic" or
179 "critical" becomes uninterruptible if called inside a code block that
180 is marked as "atomic" or "critical".
181
182 Atomic Code blocks called inside the call chain of a "critical" code
183 block do not pose a problem, as they are more restrictive.
184
185 Any code that attempts to perform any non-revertible action (e.g.
186 reading from a socket) will cause a fatal error when called inside the
187 call chain of an Atomic Code block.
188
189 Co-Routines
190 The execution of co-routine (or "coro" for short) could be considered
191 as a short "side-step" from the normal path of execution, much like the
192 normal calling of a subroutine.
193
194 The main difference with a normal subroutine, is that the co-routine
195 supports a special type of return, called "yield".
196
197 (EM: not sure whether the "threads->yield" causes so much mental
198 interference that we should use something else for "yield" in the coro
199 context. And whether we should have a seperate "coro" keyword at all:
200 after all, the "yield" could be in a normal subroutine called from a
201 coro, so it's not like the compiler would be allowed to flag "yield" in
202 a sub as an error).
203
204 #######################################################################
205 Below here still the more or less unorganized stuff
206
207 CORE::GLOBAL::exit; # kills all the threads
208
209 # We intententionally do not list cross-machine parallelism Conc::
210 classes here. # Consult your local 6PAN mirror with a time machine.
211 use Conc::Processes; # fork() or createProcess based implementation use
212 Conc::Threads; # maybe it just exports &async to override the default
213 one, yay use Conc::Multiplex; # this is default
214
215 my $thr = async {
216 ...do something...
217 END { } };
218
219 Conc::Thread.this Conc::Proc.this
220
221 Conc object # name is still up for grabs! - numify to TIDs (as in
222 pugs) - stringify to something sensible (eg. "<Conc:tid=5>"); -
223 enumerable with Conc.list - Conc.yield (if this is to live but
224 deprecated, maybe call it sleep(0)?) - sleep() always respects other
225 threads, thank you very much - standard methods:
226 - .join # wait for invocant to finish (always item cxt)
227 - .die # throw exception in the invocant thread
228 - .alarm # set up alarms
229 - .alarms # query existing alarms
230 - .suspend # pause a thread; fail if already paused
231 - .resume # revive a thread; fail if already running
232 - .detach # survives parent thread demise (promoted to process)
233 # process-local changes no longer affects parent
234 # tentatively, the control methods still applies to it
235 # including wait (which will always return undef)
236 # also needs to discard any atomicity context -
237 attributes:
238 - .started # time
239 - .finished # time
240 - .waiting # suspened (not diff from block on wakeup signal)
241 # waiting on a handle, a condition, a lock, et cetera
242 # otherwise returns false for running threads
243 # if it's finished then it's undef(?)
244 - .current_continuation
245 # the CC currently running in that thread
246
247 - "is throttled" trait
248
249 method throttled::trait_auxillary:<is> ($limit=1, :$key=gensym()) {
250 # "is throttled" limits max connection to this Code object
251 # the throttling is shared among closures with the same key
252 # the limit may differ on closures with the same key.
253 # if the counter with the "key" equals or exceeds a closure's limit,
254 # the closure can't be entered until it's released
255 # (this can be trivially implmented using atomic+retry)
256 }
257
258 class Foo {
259 method a is throttled(:limit(3) :key<blah>) { ... }
260 method b is throttled(:limit(2) :key<blah>) { ... }
261 }
262 my Foo $f .= new;
263 async { $f.a }
264 async { $f.b }
265
266 - Thread::Status - IO objects and containers gets concurrency love!
267 - $obj.wake_on_readable
268 - $obj.wake_on_writable
269 - $obj.wake_on_either_readable_or_writable_or_passed_time(3); #
270 fixme fixme
271 - $obj.wake_on:{.readable} # busy wait, probably
272
273 my @a is Array::Chan = 1..Inf;
274 async { @a.push(1) };
275 async { @a.blocking_shift({ ... }) };
276 async { @a.unshift({ ... }) };
277
278 Communication abstractions - shared, transactional variables by default
279
280 # program will wait for _all_ threads # unjoined threads will be joined
281 at the beginning of the END block batch # of the parent thread that
282 spawned them
283
284 ### INTERFACE BARRIER ### module Blah; {
285
286 is atomic; # retry/orelse/whatever other rollback stuff
287 # limitation: no external IO (without lethal warnings anyway)
288 # can't do anything irreversible
289
290 is critical; # free to do anything irreversible
291 # means "don't interrupt me"
292 # in system with critical section, no interrupts from
293 # other threads will happen during execution
294 # you can't suspend me
295
296 my $boo is export;
297 $boo = 1;
298
299 # We decree that this part forms the static interface
300 # it's run once during initial compilation under the
301 # Separate Compilation doctrine and the syms sealed off
302 # to form part fo bytecode syms headers
303 %CALLER::<&blah> = { 1 }; # work - adds to export set
304 die "Eureka!" if %CALLER::<$sym>; # never dies
305
306 # BEGIN { $boo = time };
307
308 sub IMPORT {
309 # VERY DYNAMIC!
310
311 our $i = time;
312 %CALLER::<&blah> = { 1 }; # work - adds to export set
313 die "Eureka!" if %CALLER::<$sym>; # probes interactively
314 }
315 }
316 ### INTERFACE BARRIER ###
317
318 my $sym; threads.new({
319 use Blah;
320 BEGIN { require(Blah).import }
321
322 my $boo; BEGIN { eval slurp<Blah.pm>; $boo := $Blah::boo };
323
324 ...
325 });
326
327 Signals
328 Asynchronous exceptions are just like user-initiated exceptions with
329 "die", so you can also catch it with regular "CATCH" blocks as
330 specified in S04.
331
332 To declare your main program catches INT signals, put a CATCH block
333 anywhere in the toplevel to handle exceptions like this:
334
335 CATCH {
336 when Error::Signal::INT { ... }
337 }
338
339 Alarm
340 An alarm is just a pre-arranged exception to be delivered to your
341 program.
342
343 By the time alarm has arrived, the current block may have already
344 finished executing, so you would need to set up CATCH blocks in places
345 where an alarm can rise to handle it properly.
346
347 You can request an alarm using the number of seconds, or with a target
348 date. It returns a proxy alarm object that you can do interesting
349 things with.
350
351 multi Alarm *alarm (Num $seconds = $CALLER::_, &do = {die Sig::ALARM}, :$repeat = 1)
352 multi Alarm *alarm (Date $date, &do = {die Sig::ALARM}, :$repeat = 1)
353
354 Perl 6's "alarm" has three additional features over traditional alarms:
355
356 Multiple and Lexical Alarms
357
358 One can set up multiple alarms using repeated alarm calls:
359
360 {
361 my $a1 = alarm(2);
362 my $a2 = alarm(2);
363 sleep 10;
364 CATCH {
365 is critical; # if you don't want $a2 to be raised inside this
366 when Sig::ALARM { ... }
367 }
368 }
369
370 To stop an alarm, call "$alarm.stop". The "alarms" method for Conc
371 objects (including process and threads) returns a list of alarms
372 currently scheduled for that concurrent context.
373
374 When an alarm object is garbage collected, the alarm is stopped
375 automatically. Under void context, the implicit alarm object can only
376 be stopped by querying ".alarms" on the current process.
377
378 We are not sure what alarm(0) would mean. Probably a deprecation
379 warning?
380
381 Repeated Alarms
382
383 If you request a repeated alarm using the "repeated" named argument, it
384 will attempt to fire off the alarm that many times. However, the alarm
385 will be supressed when inside a "CATCH" block that's already handling
386 the exception raised by same alarm.
387
388 To repeat 0 times is to not fire off any alarms at all. To repeat +Inf
389 times is to repeat over and over again.
390
391 Callbacks in Alarms
392
393 You can arrange a callback (like JavaScript's setTimeOut) in "alarm",
394 which will then be invoked with the then-current code as caller.
395
396 If you set up such a callback to another Conc object, what happens is
397 just like when you called ".die" on behalf of that object -- namely,
398 the callback closure, along with anything it referenced, is shared to
399 the target Conc context.
400
401 Unlike in Perl 5's ithreads where you cannot share anything after the
402 fact, this allows passing shared objects in an "ad-hoc" fashion across
403 concurrent parts of the program. Under the default (multiplexing)
404 concurrency model, this is basically a no-op.
405
406 Continuations
407 Coroutines
408
409 ## braindump of coro meeting by Liz and Autri, more to follow
410
411 - Coros are _like_ processes
412
413 coro dbl { yield $_ * 2; yield $_; return }; my @x = 1..10; my %y = map
414 &dbl, @x; # 2 => 2, 6 => 4, 10 => 6, ...
415
416 coro perm (@x) {
417 @x.splice(rand(@x),1).yield while @x; }
418
419 my &p1 := &perm.start(1..10); my &p2 := &perm.start(1..20);
420
421 p1(); p1(); p2(); p2();
422
423 coro foo { yield 42 };
424
425 (1..10).pick;
426
427 coro foo ($x) {
428 yield $x;
429 yield $x+2;
430 cleanup();
431 while (2) {
432 while (1) {
433 &?SUB.kill; # seppuku
434 }
435 } } # implicit falloff return + return() means startover without
436 yielding
437 # return() means yielding and restart + no implicit falloff (I LIKE
438 THIS)
439
440 &foo.finished; # true on return() and false on midway yield()
441
442 foo(4); # and that's all she wrote
443
444 coro foo ($x) {
445 yield $x;
446 # this point with $x bound to 10
447 yield $x+1;
448 return 5;
449 ... # this is never reached, I think we all agree }
450
451 # If you don't want your variables to get rebound, use "is copy": coro
452 foo ($x is copy) {...} # which is sugar for coro foo ($x) {
453 {
454 my $x := $OUTER::x;
455 ...;
456 # Further calls of &foo rebound $OUTER::x, not $x.
457 } }
458
459 sub foo {
460 return undef if rand;
461 ... }
462
463 use overload {
464 '&{}' => sub { ... } }
465
466 class Coro is Conc::Multiplex does Code {
467 method postcircumfix:<( )> {
468 # start the thread, block stuff (we are in the caller's
469 context)
470 } }
471
472 class Hash is extended {
473 method postcircumfix:<( )> (&self: *@_) {
474 &self = ./start(@_);
475 }
476 method start {
477 # remember self
478 # upon return() or normal falloff, restore self
479 } }
480
481 %ENV(123);
482
483 &foo_continued := &foo.start(10); &foo.start(20);
484
485 foo(10); # returns 10
486
487 foo(); # be "insufficient param" error or just return 11?
488 foo(20); # returns 21
489
490 # continuation coros multi foo () { ...no rebinding... } multi foo ($x)
491 { ...rebinding... }
492
493 &foo.kill;
494
495 my $first_ret = zoro( type => <even> );
496 &zoro.variant(:type<even>).kill; &zoro.variant(type => 'even').kill;
497
498 zoro( type => <odd> );
499
500 zoro( even => 1 ); zoro( odd => 1 );
501
502 multi coro zoro ($type where 'even') {} multi coro zoro ($type where
503 'odd') {}
504
505 multi coro zoro ($even is named) {} multi coro zoro ($odd is named) {}
506
507 # iblech's thoughts: # Coroutine parameters should never be rebound.
508 Instead, yield(...)s return # value is an Arglist object containing the
509 new arguments: coro bar ($a, $b) {
510 ...;
511 my $new_set_of_args = yield(...);
512 my $sum_of_old_a_and_new_a = $a + $new_set_of_args<$a>;
513 ...; } bar(42, 23); # $a is 42, $b is 23 bar(17, 19); # $a still
514 42, $b still 19,
515 # $new_set_of_args is \(a => 17, b => 19)
516
517 Junctive Autothreading and Hyper Operations
518 Live in userland for the time being.
519
520 Interprocess Communication
521 I/O Considerations
522 File Descriptors
523
524 Sockets
525
526
527
528perl v5.12.0 2006-02-28 Perl6::Bible::S17(3)