NAME
Mthreads - a userlevel thread package
SYNOPSIS
The mthreads userlevel thread package is a library that offers high efficient thread creation, synchronization and termination. User may create a huge number of threads that are distributed onto the the available processors of the specific underlying computer system. Numerous options make it possible to optimize the package's performance both, with respect to the application that uses this package as well as to the hardware the application is intended to run on.
DESCRIPTION
The mthreads package is devided into several parts: functions dealing with threads, functions for the thread package as a whole and functions for synchronizations.

Thread functions:

Thread package functions:

All synchronization mechanisms follow a simple scheme. The user has to aquire a handle for the mechanism calling some new_... function which allocates the mechanism and initializes it appropriate. After using the mechanism it is freed by a call to the corresponding delete_... function. These functions asure efficient allocation and correct alignment that cannot be garanteed for static or dynamic memory from the compiler.

Synchronization with condition variables:

Synchronization with mutex locks: Synchronization with semaphores: Synchronization with barriers:
USAGE
To use the mthreads package the programmer must include the file mthread.h which declares several datatypes and the above mentioned functions.

Before starting the package, the user can change the package's configuration. This configuration usually uses machine dependent default values, so no extra configuration is necessary. Nevertheless, configuration is possible and can help to improve the performance of the target program, either because the machine configuration has changed and/or the application needs special treatment by the package. This tuning can be done by encoding application specific values into the source code by use of mthr_config(3) or on runtime by commandline options that can be evaluated by mthr_configv(3).

Calling mthr_startup(3) initializes the thread package, allocates the necessary data and starts the kernelthreads that are used as virtual processors. Whenever one of these virtual processors becomes idle it searches for the next runnable thread and starts it. So from this moment on, userlevel threads can be created by mthr_create(3) and will be scheduled on one of the idle processors.

As with usual C programs, the process terminates when it reaches the end of main() returns from main() or exits due to exit(3). This is also true for programs using the mthreads package. To terminate the execution of one specific thread, you can use mthr_exit(3). As the thread that executes main() is handled like each other userlevel thread, using mthr_exit() terminates this thread but not the whole application. On the other hand, if you intend to terminate the whole application as it has reached its end or due to some fatal error you can still use the usual exit() call. In addition to this call there exists the mthr_halt() function. In contrast to exit() this function calls a shutdown handler,i.e. some function that might do some cleanup, like flushing outputbuffers, closing files etc. before terminating the application. The default shutdown handler does nothing but terminate the application, but the user can install its own shutdown handler by a call to mthr_set_shutdownhandler().

The third implicit possibility to terminate the process is that the last userlevel thread does its mthr_exit(). This calls the shutdown handler too, so you don't have to think about which thread will be the last one and should call exit() or mthr_halt().

EXAMPLE
This (useless) example shows some of the functions described above. 100 Threads will be created. Each thread writes a message onto the screen, increments a shared counter and terminates. When the last thread terminates the own shutdown handler is executed, printing the accumulated value of the shared counter and terminating the program.

#include <stdio.h>
#include <stdlib.h>

#include "mthread.h"

mutex_p mp;
int     no_threads = 0;

void *hello(void *arg)
{
  mutex_lock(mp);
  printf("This is thread %d\n",(int)arg);
  no_threads++;
  mutex_unlock(mp);
  mthr_exit(0);
}

void own_shutdown_handler(int exitvalue)
{
  printf("%d threads have been executed\n",no_threads);
  exit(exitvalue);
}

void main(int argc, char *argv[])
{
  int i;

  /* configuring the package */
  mthr_config_v(&argc, argv);
  
  /* starting the package */
  mthr_startup();

  /* set our own shutdown handler */
  mthr_set_shutdownhandler(own_shutdown_handler);

  /* create a mutex lock and some threads */
  mp = new_mutex();
  for(i=0;i<100;i++)
    mthr_create(0, DETACHED, hello, (void *)i);

  /* terminate the main thread */
  mthr_exit(0);

}

COMPILING
To compile applications with mthreads correctly, not only the library libmthread.a has to be linked with the application, but also some other issues have to be noticed.

The mthreads library is not compatible to the cps library, as it allocates kernelthreads itself. Therefore applications may not be linked with the cps library. Using the standard CONVEX compiler, this library is automatically linked, so it's better to link the application manually using ld(1).

A typical call to ld(1) might look like:

/usr/convex/bin/ld /usr/convex/all/crt0.o application.o +tmspp1 +over -lmthread -lqt -lail -lc

This example assumes that all libraries are in default directories. Other directories can be specified by the environment variable LD_LIBRARY_PATH or by the linker option -L.

BUGS
It is still not possible to profile applications written with mthreads with cxpa(1) as this relies on features of the cps library. As mthreads is not compatible with this library, cxpa couldn't collect profiling information.

The debugger cxdb seems to have problems with mthreads too. It's still not clear whether this problem is caused by mthreads, the debugger or the cps library again.