Thread Examples


Sum Matrix

Concurrently sum the rows of a matrix into subtotals and then sequential add the subtotals.

#include <fstream.hfa>
#include <kernel.hfa>
#include <thread.hfa>

thread Adder {
	int * row, cols, & subtotal;		// communication
};
void ?{}( Adder & adder, int row[], int cols, int & subtotal ) {
	adder.[ row, cols ] = [ row, cols ]; // expression disallowed in multi-member access
	&adder.subtotal = &subtotal;
}
void main( Adder & adder ) with( adder ) { // thread starts here
	subtotal = 0;
	for ( c; cols ) {
		subtotal += row[c];
	}
}
int main() {
	const int rows = 10, cols = 1000;
	int matrix[rows][cols], subtotals[rows], total = 0;
	processor p[3];						// add kernel thread

	for ( r; rows ) {					// initialize
		for ( c; cols ) {
			matrix[r][c] = 1;
		}
	}
	Adder * adders[rows];
	for ( r; rows ) {					// start threads to sum rows
		adders[r] = new( matrix[r], cols, subtotals[r] );
	}
	for ( r; rows ) {					// wait for threads to finish
		delete( adders[r] );
		total += subtotals[r];			// total subtotals
	}
	sout | total;
}

Quick Sort

In-place concurrent quick-sort: threads are created to partition to a specific depth, then sequential recursive-calls are use to sort each partition.

thread Quicksort {
	int * values;						// communication variables
	int low, high, depth;
};
void ?{}( Quicksort & qs, int values[], int size, int depth ) {
	qs.values = values;  qs.low = 0;  qs.high = size;  qs.depth = depth;
}
void main( Quicksort & qs ) {			// thread starts here
	// nested routines: information hiding
	void ?{}( Quicksort & qs, int values[], int low, int high, int depth ) {
		qs.values = values;  qs.low = low;  qs.high = high;  qs.depth = depth;
	}
	void sort( int values[], int low, int high, int depth ) {
		int left, right;				// index to left/right-hand side of the values
		int pivot;						// pivot value of values
		int swap;						// temporary
		// partition while 2 or more elements in the array
		if ( low < high ) {
			pivot = values[low + ( high - low ) / 2];
			left  = low;
			right = high;
			// partition: move values less < pivot before the pivot and values > pivot after the pivot
			do {
				while ( values[left] < pivot ) left += 1; // changed values[left] < pivot
				while ( pivot < values[right] ) right -= 1;
				if ( left <= right ) {
					swap = values[left]; // interchange values
					values[left]  = values[right];
					values[right] = swap;
					left += 1;
					right -= 1;
				}
			} while ( left <= right );
			// restrict number of tasks to slightly greater than number of processors
			if ( depth > 0 ) {
				depth -= 1;
				Quicksort rqs = { values, low, right, depth }; // concurrently sort upper half
				sort( values, left, high, depth ); // concurrently sort lower half
			} else {
				sort( values, low, right, 0 ); // sequentially sort lower half
				sort( values, left, high, 0 ); // sequentially sort upper half
			}
		}
	}
	with( qs ) {
		sort( values, low, high, depth );
	}
}
int main() {
	// read size, depth, unsorted values
	processor processors[ (1 << depth) - 1 ]; // create 2^depth-1 kernel threads
	Quicksort QS = { values, size - 1, depth }; // sort values
}

Go Comparison

Comparison of C∀ waitfor and Go select. Call versus channel synchronization.

C∀Go
#include <fstream.hfa>
#include <thread.hfa>

struct Msg { int i, j; };
thread Gortn { int i;  float f;  Msg m; };
void mem1( Gortn & mutex gortn, int i ) { gortn.i = i; }
void mem2( Gortn & mutex gortn, float f ) { gortn.f = f; }
void mem3( Gortn & mutex gortn, Msg m ) { gortn.m = m; }
void ^?{}( Gortn & mutex ) {}

void main( Gortn & gortn ) with( gortn ) { // thread starts

	for () {

		waitfor( mem1, gortn ) sout | i;
		or waitfor( mem2, gortn ) sout | f;
		or waitfor( mem3, gortn ) sout | m.i | m.j;
		or waitfor( ^?{}, gortn ) break;

	}

}
int main() {
	Gortn gortn;			// start thread
	mem1( gortn, 0 );		// different calls
	mem2( gortn, 2.5 );
	mem3( gortn, (Msg){ 1, 2} );


} // wait for completion
package main
import "fmt"
func main() {
	type Msg struct{ i, j int }

	ch1 := make( chan int )
	ch2 := make( chan float32 )
	ch3 := make( chan Msg )
	hand := make( chan string )
	shake := make( chan string )
	gortn := func() { // thread starts
		var i int;  var f float32;  var m Msg
		L: for {
			select { // wait for message
			  case i = <- ch1: fmt.Println( i )
			  case f = <- ch2: fmt.Println( f )
			  case m = <- ch3: fmt.Println( m )
			  case <- hand: break L // sentinel
			}
		}
		shake <- "SHAKE" // completion
	}

	go gortn()			// start thread
	ch1 <- 0			// different messages
	ch2 <- 2.5
	ch3 <- Msg{1, 2}
	hand <- "HAND"		// sentinel value
	<-shake				// wait for completion
}