 multithreaded/threadlocaldata - Maple Help Calling Sequence module() local l1::thread_local, l2::thread_local( type ); ... end module Parameters

 l1 - a local name l2 - a local name type - a type Description

 • Many algorithms maintain data during their computation.  In Maple, this data is often stored as module locals.  By default module locals are shared variables, meaning that their value can be accessed by any thread. This can make these algorithms difficult to make thread-safe.  To solve this, Maple allows module locals to be declared thread local.
 • A thread local name stores a different value for each Maple thread that accesses the name.  This means that each thread can access the value stored by that name without worrying about interactions between threads.  In particular, there is no need to use a Mutex to synchronize access to the name.
 • To declare a module local as thread local, the thread_local type modifier is used:
 > m := module()    local shrdLocal, thrLocal::thread_local;    ... end:

In this example, shrdLocal is a shared module local.  The value stored by shrdLocal can be accessed and modified by any thread.  The variable thrLocal is thread local, the value it stores is specific to a thread.

 • The thread_local modifier can also be combined with a type declaration similar to a procedure parameter modifier.  In the following example, thrlocal is declared to be thread local and of type integer.
 > m := module()    local modLocal::integer, thrLocal::thread_local(integer);    ... end:
 • In the following example, the shared module's state variable is not thread local.
 > shared := module()    local state;    export routine;    routine := proc(lo,hi)        local i;        state := 0;        for i from lo to hi        do            state := state + i;        end;        state;    end; end:
 • When run sequentially, this works as expected.
 > shared:-routine( 1, 10^6 );
 ${500000500000}$ (1)
 > shared:-routine( 10^6, 2*10^6 );
 ${1500001500000}$ (2)
 • However if these example are run in parallel the threads interfere with each other by accessing the shared state variable.
 ${1091613272852}{,}{1067065195648}$ (3)
 • By using the thread_local type modifier we can make this example work properly in parallel.
 > thrlocal := module()     local state::thread_local;     export routine;     routine := proc(lo,hi)         local i;         state := 0;         for i from lo to hi         do             state := state + i;         end;         state;     end; end;
 ${\mathrm{thrlocal}}{:=}{\mathbf{module}}\left({}\right)\phantom{\rule[-0.0ex]{0.5em}{0.0ex}}{\mathbf{local}}\phantom{\rule[-0.0ex]{0.5em}{0.0ex}}{\mathrm{state}}{::}{\mathrm{thread_local}}{;}\phantom{\rule[-0.0ex]{0.5em}{0.0ex}}{\mathbf{export}}\phantom{\rule[-0.0ex]{0.5em}{0.0ex}}{\mathrm{routine}}{;}\phantom{\rule[-0.0ex]{0.5em}{0.0ex}}{}\phantom{\rule[-0.0ex]{0.5em}{0.0ex}}{\mathbf{end module}}$ (4)
 > thrlocal:-routine( 1, 10^6 );
 ${500000500000}$ (5)
 > thrlocal:-routine( 10^6, 2*10^6 );
 ${1500001500000}$ (6)
 ${500000500000}{,}{1500001500000}$ (7) Default Values

 • A thread local variable can be assigned a default value, that is, the value that will be seen by any thread that has not yet assigned to the variable. The default value is the final value assigned to the variable during the evaluation of the module body.
 > defaults1 := module()     local state::thread_local := 1;     export get;     get := proc()         state;     end; end:
 ${1}{,}{1}$ (8)
 > defaults2 := module()     local state::thread_local := 1;     export get;     state := 2;     get := proc()         state;     end; end:
 ${2}{,}{2}$ (9)
 > defaults3 := module()     local state::thread_local := 1;     export get;     state := 2;     get := proc()         state;     end;     state := 3; end:
 ${3}{,}{3}$ (10) 