Table of Contents

Name

qt_loopaccum_balance, qt_loopaccum_balance_future - a slightly intelligent implementation of a threaded loop that returns values

Synopsis

#include <qthread/qloop.h>

void
qt_loopaccum_balance (const size_t start, const size_t stop, const size_t size, void *out, const qt_loopr_f func, void *argptr, const qt_accum_f acc);

void
qt_loopaccum_balance_future (const size_t start, const size_t stop, const size_t size, void *out, const qt_loopr_f func, void *argptr, const qt_accum_f acc);

Description

This function provides a simple C implementation of a threaded accumulating loop. Rather than using a predictable number of threads, however, the number of threads generated depends directly upon the number of shepherds available. The difference between qt_loopaccum_balance() and qt_loopaccum_balance_future() is that the former uses qthreads and the latter uses futures. The idea with the accumulation is that they can be used to collect values from multiple threads. For example, if there is a running tally of outputs, or if the maximum return value must be retained, this is a way to do it.

These function can be thought of as akin to (but not replicating exactly) the following code:

unsigned int i;
for (i = start; i < stop; i ++) {


func (NULL, argptr, ret);
acc (tmp, ret);

}

One qthread (or future) is spawned for each shepherd. The set of values of i (iterations) is divided evenly among the shepherds, and each qthread (or future) is assigned a set of iterations to perform.

The func argument must be a function pointer with a qt_loopr_f prototype. Note that this is NOT the same as qt_loop_f functions, as it has the extra ret argument. Its basic code structure is expected to look like this:

void func (const size_t startat, const size_t stopat, void *argptr, void *ret)
{


for (unsigned int i = startat; i < stopat; i++) {

/* do work */

}

}

The arguments startat and stopat are determined by the library, and tell the function what range of i values (iterations) it is responsible for. qt_loop_balance() and qt_loop_balance_future() will not return until all of the qthreads (or futures) it spawned have exited.

The acc argument must be a function pointer with a qt_accum_f prototype. This prototype looks like this:

void acc (void *a, void *b);

The accumulating value is stored in the memory pointed to by the a argument, and a new value is passed in via the b argument. Keep in mind that when there is only a single shepherd, this function is never called, as the entire set of iterations will be given to a single instance of func to perform. Because of this, and because there is no guarantee as to how the iterations will be divided, func is expected to perform essentially the same accumulation operation that acc does. There is also no guarantee as to what order things will be accumulated in, so the operation needs to be commutative if all runs of the program are expected to return the same result.

The result of the accumulations (acc), if any, of the output (ret) of func will be stored in the memory pointed to by out. This memory is assumed to be at least size bytes, and size bytes will be used for storage of all ret arguments to func calls.

Example

Since this is a bit complicated a simple example may be useful. The example is the qt_double_sum() function in the library; for simplicity’s sake, the checkfeb option has been removed from this example. This function is extremely simple:

double qt_double_sum (double *array, size_t length)
{

double ret;
qt_loopaccum_balance_future (0, length, sizeof(double), &ret, qtds_worker, array, qtds_acc);
return ret;
}

There are two function arguments to the qt_loopaccum_balance_future() call, qtds_worker (as the func argument) and qtds_acc (as the acc or "accumulator" argument). qtds_acc is extremely simple:

static void qtds_acc (void *a, void *b)
{

*(double*)a += *(double*)b;
}

The qtds_worker function does the real work of adding up the numbers:

static void qtds_worker (const size_t startat, const size_t stopat, void *array, void *ret)
{

size_t i;
double sum = (double *)array[startat];
for (i = startat + 1; i < stopat; i++) {
sum += (double *)array[i];
}
*(double *)ret = sum;
}

See Also

qt_loop(3) , qt_loop_future(3) , qt_loop_balance(3) , qt_loop_balance_future(3)


Table of Contents