1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
* About:
native API is a collection of functions with a prefix "myth_". With native API, you can use full functionalities of MassiveThreads such as work stealing strategy customization.
* Tutorial:
** How to compile and link with native API:
Please include myth.h in ${prefix}/include and link libmyth.so or libmyth-native.so in ${prefix}/lib.
${prefix} shows a directory where MassiveThreads is installed. Please change accordingly.
Example:
$ cat foo.c
#include <myth.h>
int main(int argc,char **argv)
{
myth_init();
printf("Hello, MassiveThreads!\n");
myth_fini();
return 0;
}
$ gcc -o foo foo.c -I${prefix}/include -L${prefix}/lib -lmyth
** Initialization and cleanup
Before calling main function, the MassiveThreads library is automatically initialized with a default configuration, thus explicit initialization is not essentially needed. By calling initialization function explicitly, several paramteres can be controlled from application.
myth_init initializes the library with a default configuration, and myth_init_withparam takes the number of worker threads and the default stack size.
The order of priority is the following:
1.myth_init_withparam arguments
2.environmental variables
3.built-in values
Similarly, explicit cleanup is not needed because the MassiveThreads library is automaticaly cleaned up after main function is finished. But programmers can do it explicitly by calling a function myth_fini.
Examples:
/*
* The simplest example
* Explicit initialization/cleanup are not needed
*/
int main(int argc, chart **argv)
{
/* Do something here */
return 0;
}
/* Explicit initialization with specifying the number of workers and stack size manually */
int main(int argc, chart **argv)
{
int n_workers;
size_t stack_size;
n_workers=atoi(argv[1]);
stack_size=(size_t)atoi(argv[2]);
myth_init_withparam(n_workers,stack_size);
/* Do something here */
myth_fini();
return 0;
}
** Thread creation and termination
myth_create and myth_create_ex are functions to create a new thread.
myth_create creates a new thread and calls an entry point function. On success it returns a handle of new thread, otherwise NULL is returned.
myth_create_ex takes an extra argument of structure myth_thread_option which describes the configuration of a thread to be created. By filling the structure, the following parameters can be configured.
* stack_size : Stack size in bytes
* swtich_immediately : Execution strategy (0: help-first, others:work-first)
* custom_data_size : The size of the hint data (described later)
* custom_data : Initial data of the hint
myth_join is a function to wait for the termination of a thread. It takes two arguments: a handle to thread and a pointer to store the return value of the entry point function. If return value is not needed, NULL can be specified as second argument.
myth_detach is a function to release the resource of the thread after it is finished.
These semantics are similar to those of pthread. Specifically, myth_detach or myth_join must be called ONCE for every thread.
Example:
/* Create threads recursively */
void *threadfn(void* arg)
{
myth_thread_t th[2];
int i;
int depth=(int)arg;
if (depth<=0) return NULL;
for (i=0;i<2;i++){
th[i]=myth_create(threadfn,(void*)(depth-1));
}
for (i=0;i<2;i++){
myth_join(th[i],NULL);
}
return NULL;
}
* Thread and worker properties
The MassiveThreads library provides 3 functions to acquire properties of thread and its underlying worker thread.
myth_get_worker_num returns an ID of the underlying worker thread of the current thread.
myth_get_num_workers returns the number of worker threads.
myth_self returns a handle of the current thread.
* Work stealing strategy customization
Programmers can customize the strategy of work stealing by implementing an user-defined callback function invoked on work stealing. Typically, an user-defined work stealing function is implemented by the following 5 steps:
1. Select the candidates of worker threads to steal
2. Read hint data of tasks that are available from candidates
3. Choose one candidate as target of work stealing
3. Try to steal
4. (Optional) commit the steal if an actually stolen task is good to be executed
The following subsections describe building blocks to implement a customized work stealing function.
** Thread-local hint data
Prgrammers can give data for each thread as a hint of work stealing.
myth_wsapi_set_hint function gives hint data to a thread and returns the previous hint data.
myth_create_ex can also be used to give hint data. (see "Thread creation and termination")
myth_wsapi_get_hint_ptr returns a pointer to the hint data. Similarly, myth_wsapi_get_hint_size returns a size of the hint.
** Candidate selection
myth_wsapi_rand gives a random integer from 0 to (myth_get_num_workers()-1).
myth_wsapi_randarr gives a non-duplicated list of random integers from 0 to (myth_get_num_workers()-1).
** Runqueue operation
myth_wsapi_runqueue_peek reads a hint from a task which can be stolen from the specified worker thread, and returns a copy of it.
myth_wsapi_runquque_take tries to steal a task from the specified victim. Programmers can also specify a user-defined callback function which is called when the steal attempt is about to be succeeded. The purpose of the callback function is to check whether an actually stolen task is good to be executed on the worker thread. If the function returns non-zero, the steal is committed, otherwise it is cancelled.
** Work stealing function override
By calling myth_wsapi_set_stealfunc, programmers can override the default work stealing function to user-defined one.
|