@@ -402,22 +402,6 @@ freeing memory along the way---and then exits. Unlike exceptions in C++,
402402exceptions in Rust are unrecoverable within a single task: once a task fails,
403403there is no way to "catch" the exception.
404404
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-
421405While it isn't possible for a task to recover from failure, tasks may notify
422406each other of failure. The simplest way of handling task failure is with the
423407` 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
464448might want to contain the failure at a certain boundary (perhaps a
465449small piece of input from the outside world, which you happen to be
466450processing 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).
562452
563453## Creating a task with a bi-directional communication path
564454
0 commit comments