@@ -402,22 +402,6 @@ freeing memory along the way---and then exits. Unlike exceptions in C++,
402
402
exceptions in Rust are unrecoverable within a single task: once a task fails,
403
403
there is no way to "catch" the exception.
404
404
405
- All tasks are, by default, _ linked_ to each other. That means that the fates
406
- of all tasks are intertwined: if one fails, so do all the others.
407
-
408
- ~~~ {.xfail-test .linked-failure}
409
- # use std::task::spawn;
410
- # use std::task;
411
- # fn do_some_work() { loop { task::yield() } }
412
- # do task::try {
413
- // Create a child task that fails
414
- do spawn { fail!() }
415
-
416
- // This will also fail because the task we spawned failed
417
- do_some_work();
418
- # };
419
- ~~~
420
-
421
405
While it isn't possible for a task to recover from failure, tasks may notify
422
406
each other of failure. The simplest way of handling task failure is with the
423
407
` try ` function, which is similar to ` spawn ` , but immediately blocks waiting
@@ -464,101 +448,7 @@ it trips, indicates an unrecoverable logic error); in other cases you
464
448
might want to contain the failure at a certain boundary (perhaps a
465
449
small piece of input from the outside world, which you happen to be
466
450
processing in parallel, is malformed and its processing task can't
467
- proceed). Hence, you will need different _ linked failure modes_ .
468
-
469
- ## Failure modes
470
-
471
- By default, task failure is _ bidirectionally linked_ , which means that if
472
- either task fails, it kills the other one.
473
-
474
- ~~~ {.xfail-test .linked-failure}
475
- # use std::task;
476
- # use std::comm::oneshot;
477
- # fn sleep_forever() { loop { let (p, c) = oneshot::<()>(); p.recv(); } }
478
- # do task::try {
479
- do spawn {
480
- do spawn {
481
- fail!(); // All three tasks will fail.
482
- }
483
- sleep_forever(); // Will get woken up by force, then fail
484
- }
485
- sleep_forever(); // Will get woken up by force, then fail
486
- # };
487
- ~~~
488
-
489
- If you want parent tasks to be able to kill their children, but do not want a
490
- parent to fail automatically if one of its child task fails, you can call
491
- ` task::spawn_supervised ` for _ unidirectionally linked_ failure. The
492
- function ` task::try ` , which we saw previously, uses ` spawn_supervised `
493
- internally, with additional logic to wait for the child task to finish
494
- before returning. Hence:
495
-
496
- ~~~ {.xfail-test .linked-failure}
497
- # use std::comm::{stream, Chan, Port};
498
- # use std::comm::oneshot;
499
- # use std::task::{spawn, try};
500
- # use std::task;
501
- # fn sleep_forever() { loop { let (p, c) = oneshot::<()>(); p.recv(); } }
502
- # do task::try {
503
- let (receiver, sender): (Port<int>, Chan<int>) = stream();
504
- do spawn { // Bidirectionally linked
505
- // Wait for the supervised child task to exist.
506
- let message = receiver.recv();
507
- // Kill both it and the parent task.
508
- assert!(message != 42);
509
- }
510
- do try { // Unidirectionally linked
511
- sender.send(42);
512
- sleep_forever(); // Will get woken up by force
513
- }
514
- // Flow never reaches here -- parent task was killed too.
515
- # };
516
- ~~~
517
-
518
- Supervised failure is useful in any situation where one task manages
519
- multiple fallible child tasks, and the parent task can recover
520
- if any child fails. On the other hand, if the _ parent_ (supervisor) fails,
521
- then there is nothing the children can do to recover, so they should
522
- also fail.
523
-
524
- Supervised task failure propagates across multiple generations even if
525
- an intermediate generation has already exited:
526
-
527
- ~~~ {.xfail-test .linked-failure}
528
- # use std::task;
529
- # use std::comm::oneshot;
530
- # fn sleep_forever() { loop { let (p, c) = oneshot::<()>(); p.recv(); } }
531
- # fn wait_for_a_while() { for _ in range(0, 1000u) { task::yield() } }
532
- # do task::try::<int> {
533
- do task::spawn_supervised {
534
- do task::spawn_supervised {
535
- sleep_forever(); // Will get woken up by force, then fail
536
- }
537
- // Intermediate task immediately exits
538
- }
539
- wait_for_a_while();
540
- fail!(); // Will kill grandchild even if child has already exited
541
- # };
542
- ~~~
543
-
544
- Finally, tasks can be configured to not propagate failure to each
545
- other at all, using ` task::spawn_unlinked ` for _ isolated failure_ .
546
-
547
- ~~~ {.xfail-test .linked-failure}
548
- # use std::task;
549
- # fn random() -> uint { 100 }
550
- # fn sleep_for(i: uint) { for _ in range(0, i) { task::yield() } }
551
- # do task::try::<()> {
552
- let (time1, time2) = (random(), random());
553
- do task::spawn_unlinked {
554
- sleep_for(time2); // Won't get forced awake
555
- fail!();
556
- }
557
- sleep_for(time1); // Won't get forced awake
558
- fail!();
559
- // It will take MAX(time1,time2) for the program to finish.
560
- # };
561
- ~~~
451
+ proceed).
562
452
563
453
## Creating a task with a bi-directional communication path
564
454
0 commit comments