… | |
… | |
66 | CORO THREAD LIFE CYCLE |
66 | CORO THREAD LIFE CYCLE |
67 | During the long and exciting (or not) life of a coro thread, it goes |
67 | During the long and exciting (or not) life of a coro thread, it goes |
68 | through a number of states: |
68 | through a number of states: |
69 | |
69 | |
70 | 1. Creation |
70 | 1. Creation |
71 | The first thing in the life of a coro thread is it's creation - |
71 | The first thing in the life of a coro thread is its creation - |
72 | obviously. The typical way to create a thread is to call the "async |
72 | obviously. The typical way to create a thread is to call the "async |
73 | BLOCK" function: |
73 | BLOCK" function: |
74 | |
74 | |
75 | async { |
75 | async { |
76 | # thread code goes here |
76 | # thread code goes here |
… | |
… | |
85 | This creates a new coro thread and puts it into the ready queue, |
85 | This creates a new coro thread and puts it into the ready queue, |
86 | meaning it will run as soon as the CPU is free for it. |
86 | meaning it will run as soon as the CPU is free for it. |
87 | |
87 | |
88 | "async" will return a Coro object - you can store this for future |
88 | "async" will return a Coro object - you can store this for future |
89 | reference or ignore it - a thread that is running, ready to run or |
89 | reference or ignore it - a thread that is running, ready to run or |
90 | waiting for some event is alive on it's own. |
90 | waiting for some event is alive on its own. |
91 | |
91 | |
92 | Another way to create a thread is to call the "new" constructor with |
92 | Another way to create a thread is to call the "new" constructor with |
93 | a code-reference: |
93 | a code-reference: |
94 | |
94 | |
95 | new Coro sub { |
95 | new Coro sub { |
… | |
… | |
239 | implements an endless loop, the $guard will not be cleaned up. |
239 | implements an endless loop, the $guard will not be cleaned up. |
240 | However, since the thread object returned by "async" is not stored |
240 | However, since the thread object returned by "async" is not stored |
241 | anywhere, the thread is initially referenced because it is in the |
241 | anywhere, the thread is initially referenced because it is in the |
242 | ready queue, when it runs it is referenced by $Coro::current, but |
242 | ready queue, when it runs it is referenced by $Coro::current, but |
243 | when it calls "schedule", it gets "cancel"ed causing the guard |
243 | when it calls "schedule", it gets "cancel"ed causing the guard |
244 | object to be destroyed (see the next section), and printing it's |
244 | object to be destroyed (see the next section), and printing its |
245 | message. |
245 | message. |
246 | |
246 | |
247 | If this seems a bit drastic, remember that this only happens when |
247 | If this seems a bit drastic, remember that this only happens when |
248 | nothing references the thread anymore, which means there is no way |
248 | nothing references the thread anymore, which means there is no way |
249 | to further execute it, ever. The only options at this point are |
249 | to further execute it, ever. The only options at this point are |
… | |
… | |
252 | 5. Cleanup |
252 | 5. Cleanup |
253 | Threads will allocate various resources. Most but not all will be |
253 | Threads will allocate various resources. Most but not all will be |
254 | returned when a thread terminates, during clean-up. |
254 | returned when a thread terminates, during clean-up. |
255 | |
255 | |
256 | Cleanup is quite similar to throwing an uncaught exception: perl |
256 | Cleanup is quite similar to throwing an uncaught exception: perl |
257 | will work it's way up through all subroutine calls and blocks. On |
257 | will work its way up through all subroutine calls and blocks. On its |
258 | it's way, it will release all "my" variables, undo all "local"'s and |
258 | way, it will release all "my" variables, undo all "local"'s and free |
259 | free any other resources truly local to the thread. |
259 | any other resources truly local to the thread. |
260 | |
260 | |
261 | So, a common way to free resources is to keep them referenced only |
261 | So, a common way to free resources is to keep them referenced only |
262 | by my variables: |
262 | by my variables: |
263 | |
263 | |
264 | async { |
264 | async { |
… | |
… | |
284 | those code blocks): |
284 | those code blocks): |
285 | |
285 | |
286 | async { |
286 | async { |
287 | my $window = new Gtk2::Window "toplevel"; |
287 | my $window = new Gtk2::Window "toplevel"; |
288 | # The window will not be cleaned up automatically, even when $window |
288 | # The window will not be cleaned up automatically, even when $window |
289 | # gets freed, so use a guard to ensure it's destruction |
289 | # gets freed, so use a guard to ensure its destruction |
290 | # in case of an error: |
290 | # in case of an error: |
291 | my $window_guard = Guard::guard { $window->destroy }; |
291 | my $window_guard = Guard::guard { $window->destroy }; |
292 | |
292 | |
293 | # we are safe here |
293 | # we are safe here |
294 | }; |
294 | }; |
… | |
… | |
629 | call and the arguments, but consumes very little other resources. |
629 | call and the arguments, but consumes very little other resources. |
630 | New states will automatically get assigned a perl interpreter when |
630 | New states will automatically get assigned a perl interpreter when |
631 | they are transferred to. |
631 | they are transferred to. |
632 | |
632 | |
633 | $state->is_zombie |
633 | $state->is_zombie |
634 | Returns true iff the Coro object has been cancelled, i.e. it's |
634 | Returns true iff the Coro object has been cancelled, i.e. its |
635 | resources freed because they were "cancel"'ed, "terminate"'d, |
635 | resources freed because they were "cancel"'ed, "terminate"'d, |
636 | "safe_cancel"'ed or simply went out of scope. |
636 | "safe_cancel"'ed or simply went out of scope. |
637 | |
637 | |
638 | The name "zombie" stems from UNIX culture, where a process that has |
638 | The name "zombie" stems from UNIX culture, where a process that has |
639 | exited and only stores and exit status and no other resources is |
639 | exited and only stores and exit status and no other resources is |
… | |
… | |
783 | from multiple threads, and all will be resumed and given the status |
783 | from multiple threads, and all will be resumed and given the status |
784 | return once the $coro terminates. |
784 | return once the $coro terminates. |
785 | |
785 | |
786 | $coro->on_destroy (\&cb) |
786 | $coro->on_destroy (\&cb) |
787 | Registers a callback that is called when this coro thread gets |
787 | Registers a callback that is called when this coro thread gets |
788 | destroyed, that is, after it's resources have been freed but before |
788 | destroyed, that is, after its resources have been freed but before |
789 | it is joined. The callback gets passed the terminate/cancel |
789 | it is joined. The callback gets passed the terminate/cancel |
790 | arguments, if any, and *must not* die, under any circumstances. |
790 | arguments, if any, and *must not* die, under any circumstances. |
791 | |
791 | |
792 | There can be any number of "on_destroy" callbacks per coro, and |
792 | There can be any number of "on_destroy" callbacks per coro, and |
793 | there is currently no way to remove a callback once added. |
793 | there is currently no way to remove a callback once added. |