--- cvsroot/Coro/Coro.pm 2012/12/07 22:37:24 1.313 +++ cvsroot/Coro/Coro.pm 2015/10/16 23:41:58 1.338 @@ -197,8 +197,8 @@ Coro::terminate "return value 1", "return value 2"; }; -And yet another way is to C<< ->cancel >> (or C<< ->safe_cancel >>) the -coro thread from another thread: +Yet another way is to C<< ->cancel >> (or C<< ->safe_cancel >>) the coro +thread from another thread: my $coro = async { exit 1; @@ -220,12 +220,13 @@ when a thread is in a C method or an C for example) is safe. -Lastly, a coro thread object that isn't referenced is C<< ->cancel >>'ed -automatically - just like other objects in Perl. This is not such a common -case, however - a running thread is referencedy b C<$Coro::current>, a -thread ready to run is referenced by the ready queue, a thread waiting -on a lock or semaphore is referenced by being in some wait list and so -on. But a thread that isn't in any of those queues gets cancelled: +Last not least, a coro thread object that isn't referenced is C<< +->cancel >>'ed automatically - just like other objects in Perl. This +is not such a common case, however - a running thread is referencedy by +C<$Coro::current>, a thread ready to run is referenced by the ready queue, +a thread waiting on a lock or semaphore is referenced by being in some +wait list and so on. But a thread that isn't in any of those queues gets +cancelled: async { schedule; # cede to other coros, don't go into the ready queue @@ -234,6 +235,28 @@ cede; # now the async above is destroyed, as it is not referenced by anything. +A slightly embellished example might make it clearer: + + async { + my $guard = Guard::guard { print "destroyed\n" }; + schedule while 1; + }; + + cede; + +Superficially one might not expect any output - since the C +implements an endless loop, the C<$guard> will not be cleaned up. However, +since the thread object returned by C is not stored anywhere, the +thread is initially referenced because it is in the ready queue, when it +runs it is referenced by C<$Coro::current>, but when it calls C, +it gets Ced causing the guard object to be destroyed (see the next +section), and printing it's message. + +If this seems a bit drastic, remember that this only happens when nothing +references the thread anymore, which means there is no way to further +execute it, ever. The only options at this point are leaking the thread, +or cleaning it up, which brings us to... + =item 5. Cleanup Threads will allocate various resources. Most but not all will be returned @@ -261,12 +284,12 @@ async { my $lock_guard = $sem->guard; - # if we reutrn, or die or get cancelled, here, + # if we return, or die or get cancelled, here, # then the semaphore will be "up"ed. }; The C function comes in handy for any custom cleanup you -might want to do (but you cannot switch to other coroutines form those +might want to do (but you cannot switch to other coroutines from those code blocks): async { @@ -293,11 +316,12 @@ Even after a thread has terminated and cleaned up its resources, the Coro object still is there and stores the return values of the thread. -The means the Coro object gets freed automatically when the thread has -terminated and cleaned up and there arenot other references. +When there are no other references, it will simply be cleaned up and +freed. -If there are, the Coro object will stay around, and you can call C<< -->join >> as many times as you wish to retrieve the result values: +If there areany references, the Coro object will stay around, and you +can call C<< ->join >> as many times as you wish to retrieve the result +values: async { print "hi\n"; @@ -344,7 +368,7 @@ our $main; # main coro our $current; # current coro -our $VERSION = 6.23; +our $VERSION = 6.47; our @EXPORT = qw(async async_pool cede schedule terminate current unblock_sub rouse_cb rouse_wait); our %EXPORT_TAGS = ( @@ -630,14 +654,14 @@ $SIG{VTALRM} = sub { cede }; # and then start the interval timer Time::HiRes::setitimer &Time::HiRes::ITIMER_VIRTUAL, 0.01, 0.01; - }; + }; Coro::on_leave { # on leaving the thread, we stop the interval timer again Time::HiRes::setitimer &Time::HiRes::ITIMER_VIRTUAL, 0, 0; - }; + }; &{+shift}; - } + } # use like this: timeslice { @@ -645,7 +669,7 @@ # monopolise the process. Since it runs in a timesliced # environment, it will regularly cede to other threads. while () { } - }; + }; =item killall @@ -771,12 +795,16 @@ complicated cleanup handlers that rely on its thread context, things will not work. -Any cleanup code being run (e.g. from C blocks) will be run without -a thread context, and is not allowed to switch to other threads. On the -plus side, C<< ->cancel >> will always clean up the thread, no matter -what. If your cleanup code is complex or you want to avoid cancelling a -C-thread that doesn't know how to clean up itself, it can be better to C<< -->throw >> an exception, or use C<< ->safe_cancel >>. +Any cleanup code being run (e.g. from C blocks, destructors and so +on) will be run without a thread context, and is not allowed to switch +to other threads. A common mistake is to call C<< ->cancel >> from a +destructor called by die'ing inside the thread to be cancelled for +example. + +On the plus side, C<< ->cancel >> will always clean up the thread, no +matter what. If your cleanup code is complex or you want to avoid +cancelling a C-thread that doesn't know how to clean up itself, it can be +better to C<< ->throw >> an exception, or use C<< ->safe_cancel >>. The arguments to C<< ->cancel >> are not copied, but instead will be referenced directly (e.g. if you pass C<$var> and after the call @@ -792,11 +820,12 @@ Works mostly like C<< ->cancel >>, but is inherently "safer", and consequently, can fail with an exception in cases the thread is not in a -cancellable state. +cancellable state. Essentially, C<< ->safe_cancel >> is a C<< ->cancel >> +with extra checks before canceling. -This method works a bit like throwing an exception that cannot be caught -- specifically, it will clean up the thread from within itself, so -all cleanup handlers (e.g. C blocks) are run with full thread +It works a bit like throwing an exception that cannot be caught - +specifically, it will clean up the thread from within itself, so all +cleanup handlers (e.g. C blocks) are run with full thread context and can block if they wish. The downside is that there is no guarantee that the thread can be cancelled when you call this method, and therefore, it might fail. It is also considerably slower than C or @@ -892,7 +921,7 @@ not> die, under any circumstances. There can be any number of C callbacks per coro, and there is -no way currently to remove a callback once added. +currently no way to remove a callback once added. =item $oldprio = $coro->prio ($newprio) @@ -994,7 +1023,7 @@ you might still run into deadlocks if all event loops are blocked). Coro will try to catch you when you block in the event loop -("FATAL:$Coro::IDLE blocked itself"), but this is just best effort and +("FATAL: $Coro::idle blocked itself"), but this is just best effort and only works when you do not run your own event loop. This function allows your callbacks to block by executing them in another @@ -1108,7 +1137,7 @@ my $status = wait_for_child $pid; Coro offers two functions specifically designed to make this easy, -C and C. +C and C. The first function, C, generates and returns a callback that, when invoked, will save its arguments and notify the coro that @@ -1124,9 +1153,9 @@ sub wait_for_child($) { my ($pid) = @_; - my $watcher = AnyEvent->child (pid => $pid, cb => Coro::rouse_cb); + my $watcher = AnyEvent->child (pid => $pid, cb => rouse_cb); - my ($rpid, $rstatus) = Coro::rouse_wait; + my ($rpid, $rstatus) = rouse_wait; $rstatus } @@ -1274,10 +1303,10 @@ Low level Configuration, Thread Environment, Continuations: L. -=head1 AUTHOR +=head1 AUTHOR/SUPPORT/CONTACT - Marc Lehmann - http://home.schmorp.de/ + Marc A. Lehmann + http://software.schmorp.de/pkg/Coro.html =cut