tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Parallel tasking library



On Thu, 3 Nov 2011 23:26:07 +0000
David Holland <dholland-tech%netbsd.org@localhost> wrote:

>  > I've written a portable tasking library in C, which takes pointers
>  > to functions and then executes those functions is parallel.
> 
> Which means what? And how does it differ from passing those same
> function pointers to pthread_create? There's a wide range of
> parallelism support stuff out there already, ranging from MPI to
> Dryad, not to mention cloud cloud cloud cloud, I mean, trendy
> buzzworld-enabled packages and environments that are supposed to
> parallize across large clusters. What do you have? Which of these
> things is it like? If it's not like any of them, how and where does it
> differ?
> 
> -- 
> David A. Holland
> dholland%netbsd.org@localhost

Well the library is named libctf (for concurrent tasking framework).
The goal was to develop something simple, on top of pthreads API, in
order to make it simpler for C applications to dispatch concurrent
tasks.

The list of library features are:

- Transparent thread management. Application does not have to worry
about a thread pool, dispatching tasks and waiting for tasks to
complete. Everything is handled via simple high-level functions.

- Efficient use of resources. Threads in a thread pool can be static,
i.e. they are always present until current process exits. This cuts
down on the overhead of pthread_create() calls every time a new task is
dispatched. Threads in a thread pool can also be dynamic, i.e. after
being idle for a period of time, they call pthread_exit() and release
their resources. Such threads are dynamically created when they are
needed again. All of the above is handled automatically.

- Automatic allocation and sizing of task arguments. Tasks can be passed
any number of arguments and any number of return codes/arguments can be
collected when tasks return. Allocation of structures for task
arguments is done efficiently and transparently.

- Recursive parallelism. Concurrent tasks can create other concurrent
tasks as long as there are spare threads in a thread pool. After that
any new tasks created will execute in serial by the current thread.
This means the total number of threads is capped and will not grow
unbounded.

I've attached a sample program to illustrate how the library works. The
library needs a bit more work to make it more flexible, but I think it's
almost there. Below is the output:

atom$ CTF_THREADS_PER_GROUP=2 CTF_THREAD_GROUPS=3 ./tasks
Allocated 7 threads
Running task 1
Running task 3
Running task 2
Running task 4
Running task 5
Running task 6
Running task 0


atom$ CTF_THREADS_PER_GROUP=4 CTF_THREAD_GROUPS=4 ./tasks
Allocated 17 threads
Running task 2
Running task 3
Running task 6
Running task 4
Running task 7
Running task 10
Running task 11
Running task 13
Running task 16
Running task 12
Running task 8
Running task 15
Running task 14
Running task 0
Running task 9
Running task 5
Running task 1
#include "ctf.h"
#include <stdio.h>
#include <stdlib.h>

/* Task arguments */
struct task_arg
{
        int id;
};

/* Function executed by each task */
void *task_function(void *arg)
{
        struct task_arg *targ = (struct task_arg *)arg;

        printf("Running task %d\n", targ->id);
        return NULL;
}

int main(void)
{
        ctf_ptask_t ptask;      /* Parallel task */
        struct task_arg *targ;
        int32_t i, nthreads;

        setbuf(stdout, NULL);

        if (ctf_ptask_init(&ptask) != CTF_OK)
        {
                printf("Error, line=%d\n", __LINE__);
                exit(1);
        }

        /* Allocate all available threads in a thread pool */
        nthreads = ctf_alloc_threads(&ptask, 0);
        printf("Allocated %d threads\n", nthreads);

        /* Allocate the same number of tasks as threads */
        ctf_alloc_tasks(&ptask, nthreads);

        for (i = 0; i < nthreads; i++)
        {
                /*
                Assign a task. This sets task's function pointer, allocates 
space for
                task arguments structure, which is aligned on 8 bytes.
                */
                if (ctf_set_task(&ptask, &task_function, sizeof(struct 
task_arg), 8)
                        != CTF_OK)
                {
                        printf("Error, line=%d\n", __LINE__);
                        exit(1);
                }

                /* Get pointer to task arguments structure */
                targ = ctf_get_arg(&ptask, i);

                /* Set our arguments */
                targ->id = i;
        }

        ctf_run_tasks(&ptask);  /* Run all tasks concurrently and wait for them 
*/
        ctf_ptask_free(&ptask); /* Deallocate parallel task object */

        exit(0);
}


Home | Main Index | Thread Index | Old Index