Thread Examples
Source: https://cforall.uwaterloo.ca/features/thread.shtml Parent: https://cforall.uwaterloo.ca/features/
Sum Matrix
Concurrently sum the rows of a matrix into subtotals and then sequential add the subtotals.
#include <fstream.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; // 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] = &(*malloc()){ matrix[r], cols, subtotals[r] };
// 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 } |