1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
# Copyright (C) 2010-2012, Parrot Foundation.
# $Id$
=head1 DESCRIPTION
This file demonstrates cooperative concurrency using continuations on Parrot.
See also http://www.parrot.org/content/threads-are-continuations
=cut
=head1 th_init
First, we create an array to store unscheduled threads in. For simplicity,
this is stored in a global.
=cut
.include 'interpinfo.pasm'
.sub th_init
$P0 = new 'ResizablePMCArray'
set_global 'threads', $P0
.end
=head1 th_create
This is the 'spawn' call. It takes a sub and schedules it to run as a
thread.
=cut
.sub th_create
.param pmc in_sub
$P0 = get_global 'threads'
push $P0, in_sub
.end
=head1 th_resched
This is the 'yield' call. When called from a running thread, it saves the
current point in the computation as a continuation and runs the next thread.
=cut
.sub th_resched
.local pmc cur_th, next_th, ths
ths = get_global 'threads'
# This gets the return continuation for the currently running sub.
# When this continuation is invoked, it will be as if this call
# to th_resched just returned.
cur_th = interpinfo .INTERPINFO_CURRENT_CONT
push ths, cur_th
again:
next_th = shift ths
invokecc next_th
$I0 = ths
if $I0 > 0 goto again
.end
=head1 th_main
This starts up the thread system (after some threads have been scheduled) and makes
sure the program doesn't exit before all the threads have run to completion.
=cut
.sub th_main
.local pmc ths
again1:
ths = get_global 'threads'
$I0 = ths
if $I0 <= 0 goto done
th_resched()
goto again1
done:
.end
=head1 subs and main function
That's it. All we need now is some test threads and a main function to run them.
=cut
.sub sub1
say "sub1: Hallo"
th_resched()
say "sub1: Dance! <(\"< >\")> <(\"<"
th_resched()
say "sub1: Bye"
.end
.sub sub2
say "sub2: Hallo"
th_resched()
say "sub2: Dance! >\")> <(\"< >\")>"
th_resched()
say "sub2: Bye"
.end
.sub sub3
say "sub3: Good morning"
th_resched()
$I0 = 5
$I1 = $I0 + 3
th_resched()
print "sub3: 5 + 3 = "
say $I1
th_resched()
say "sub3: Is leaving."
.end
.sub main :main
th_init()
$P0 = get_global 'sub1'
th_create($P0)
$P0 = get_global 'sub3'
th_create($P0)
$P0 = get_global 'sub2'
th_create($P0)
th_main()
say "All done"
.end
=head1 EXPECTED OUTPUT
The program should (and does) produce this output:
sub1: Hallo
sub3: Good morning
sub2: Hallo
sub1: Dance! <("< >")> <("<
sub2: Dance! >")> <("< >")>
sub1: Bye
sub3: 5 + 3 = 8
sub2: Bye
sub3: Is leaving.
All done
=cut
# Local Variables:
# mode: pir
# fill-column: 100
# End:
# vim: expandtab shiftwidth=4 ft=pir:
|