| 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 |
--==---/ / _ \/ // /\ \/ / schmorp@schmorp.de |e| |
| 91 |
-=====/_/_//_/\_,_/ /_/\_\ XX11-RIPE --+ |
| 92 |
The choice of a GNU generation | |
| 93 |
| |
| 94 |
|