Go backward to Quicksort Go up to Tutorial Go forward to Long Integer Multiplication (Bag Version) |
#include <rt++.h> typedef char Digit; typedef Array<Digit> Number; ... // ---------------------------------------------------------------------------- // sum of two thread results // ---------------------------------------------------------------------------- Number sum(Thread<Number> ta, Thread<Number> tb) { Number a = Wait(ta); Number b = Wait(tb); ... return(s); } // ---------------------------------------------------------------------------- // product of number and digit // ---------------------------------------------------------------------------- Number prod(Number a, Digit b) { ... return(p); } // ---------------------------------------------------------------------------- // multiplication of two numbers // ---------------------------------------------------------------------------- Number mult(Number a, Number b) { int lb = Length(b); List< Thread<Number> > l; // l = Thread<Number>::Nil(); for (int i = 0; i < lb; i++) { Thread2<Number, Number, Digit> t(prod, a, b[i]); l.cons(t, l); // l = Cons(t, l); } int n = 2*lb-1; for (int j = 0; j < n-2 ; j += 2) { Thread<Number> ta(Head(l)); l.tail(); // l = Tail(l); Thread<Number> tb(Head(l)); l.tail(); // l = Tail(l); Thread2<Number, Thread<Number>, Thread<Number> > t(sum, ta, tb); l.cons(t, l); // l = Cons(t, l); } return(Wait(Head(l))); } int multmain(int argc, char *argv[]) { ... Number a(la); Number b(lb); ... Number c = mult(a, b); ... }
The core of this program is the function mult
which implements a
parallel version of the traditional school algorithm where a number is
an object of type Array<Digit>
:
There are several issues remarkable about above implementation:
List
to construct element sequences of arbitrary length. New elements can be
inserted at the head of a list and a list can be decomposed into its head
element and the tail list.
List< Thread<Number> >
i.e. each
element of a list holds a thread returning a number. The type
Thread<...>
does (in contrast to the types
Thread
n<...>
) not specify which
argument types these threads have; correspondingly it can hold any kind
of thread with the denoted result type (indeed both program phases insert
threads of different argument types into ).
The first three declarations are necessary because digits, numbers, and threads are used as thread arguments and results and stored in lists and arrays, respectively. The remaining three declarations refer to the kinds of threads used in the program. TheAtom(Digit); Ref(Number); Ref(Thread<Number>); ThreadRes(Number); ThreadArg2(A, Number, Number, Digit); ThreadArg2(B, Number, Thread<Number>, Thread<Number>);
ThreadRes<...>
declaration is
required for every kind of Thread<...>
type. If forgotten, the
linker complains with error messages as the following
mult.o(.text+0xef8): undefined reference to `Type<ResultThread<Number> >::init' mult.o(.text+0xf0b): undefined reference to `Type<ResultThread<Number> >::scan'