| 1 |
pcg |
1.1 |
From: Marc Lehmann |
| 2 |
|
|
To: "Eric G. Bergeron" |
| 3 |
|
|
Subject: Re: About the Coro module |
| 4 |
|
|
|
| 5 |
|
|
> I am starting to use your perl Coro module and I think that I noticed a |
| 6 |
|
|
|
| 7 |
|
|
Well, perl is not really coro-safe, or was it that coro is not perl-safe? |
| 8 |
|
|
:) |
| 9 |
|
|
|
| 10 |
|
|
It should work, but some corner cases, especially at global destruction, |
| 11 |
|
|
are not handled as nice as they could. |
| 12 |
|
|
|
| 13 |
|
|
> bug (I just don't know where the bug is.). This code below seems to run the |
| 14 |
|
|
> function 1 time too many. |
| 15 |
|
|
> |
| 16 |
|
|
> use Coro; |
| 17 |
|
|
> use strict; |
| 18 |
|
|
> my $proc=new Coro sub |
| 19 |
|
|
> { my $i=0; |
| 20 |
|
|
> while (1) |
| 21 |
|
|
> { print "$i "; $i++; |
| 22 |
|
|
> cede; |
| 23 |
|
|
> } |
| 24 |
|
|
> }; |
| 25 |
|
|
> $proc->ready(); |
| 26 |
|
|
> cede; |
| 27 |
|
|
> $proc->ready(); |
| 28 |
|
|
> cede; |
| 29 |
|
|
|
| 30 |
|
|
no, that's correct. "cede" is like the posix "yield" function. It |
| 31 |
|
|
doesn't take the process out of the ready queue, it just gives other |
| 32 |
|
|
processes the opportunity to run. |
| 33 |
|
|
|
| 34 |
|
|
So a single ->ready suffices to make it run as often as it wants - until |
| 35 |
|
|
the main program exits, that is. |
| 36 |
|
|
|
| 37 |
|
|
The second ->ready call is actually a bug (not fatal), as it puts the |
| 38 |
|
|
process a second time into the run queue. This is not a problem for |
| 39 |
|
|
Coro, but not expected by you :) |
| 40 |
|
|
|
| 41 |
|
|
If you want to switch to another coro _without_ being put into the ready |
| 42 |
|
|
queue automatically, don't use "cede" but "schedule". Schedule just |
| 43 |
|
|
switches to another process and leaves the current one alone, while cede |
| 44 |
|
|
is just a temporary switch - it will return later. |
| 45 |
|
|
|
| 46 |
|
|
Think of coros as processes. The Coro::State and Coro::Cont modules |
| 47 |
|
|
implement different ideas, so you could roll your own stuff if you really |
| 48 |
|
|
wanted to. |
| 49 |
|
|
|
| 50 |
|
|
A simple (althogh difficult to read) example is in one of the many |
| 51 |
|
|
semaphore modules (e.g. Coro::Signal). The wait method for example: |
| 52 |
|
|
|
| 53 |
|
|
sub wait { |
| 54 |
|
|
if ($_[0][0]) { |
| 55 |
|
|
$_[0][0] = 0; |
| 56 |
|
|
} else { |
| 57 |
|
|
push @{$_[0][1]}, $Coro::current; # <- here |
| 58 |
|
|
Coro::schedule; # <- here |
| 59 |
|
|
} |
| 60 |
|
|
} |
| 61 |
|
|
|
| 62 |
|
|
It first remembers the "current" process (the calling coro) internally |
| 63 |
|
|
and then calls schedule, which cuases the process to stop running |
| 64 |
|
|
immediately. Unless somebody else wakes it up it'll never run again. |
| 65 |
|
|
"send" does this: |
| 66 |
|
|
|
| 67 |
|
|
sub send { |
| 68 |
|
|
if (@{$_[0][1]}) { |
| 69 |
|
|
(shift @{$_[0][1]})->ready; # <- here |
| 70 |
|
|
} else { |
| 71 |
|
|
$_[0][0] = 1; |
| 72 |
|
|
} |
| 73 |
|
|
} |
| 74 |
|
|
|
| 75 |
|
|
It puts the waiting process into thr ready queue again. |
| 76 |
|
|
|
| 77 |
|
|
"cede" is implemented like this (in C, but the basic idea is the same): |
| 78 |
|
|
|
| 79 |
|
|
sub cede { |
| 80 |
|
|
$current->ready; |
| 81 |
|
|
schedule; |
| 82 |
|
|
} |
| 83 |
|
|
|
| 84 |
|
|
so it put's itself into the ready queue and calls the scheduler. |
| 85 |
|
|
|
| 86 |
|
|
-- |
| 87 |
|
|
-----==- | |
| 88 |
|
|
----==-- _ | |
| 89 |
|
|
---==---(_)__ __ ____ __ Marc Lehmann +-- |
| 90 |
|
|
--==---/ / _ \/ // /\ \/ / pcg@goof.com |e| |
| 91 |
|
|
-=====/_/_//_/\_,_/ /_/\_\ XX11-RIPE --+ |
| 92 |
|
|
The choice of a GNU generation | |
| 93 |
|
|
| |
| 94 |
|
|
|