Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29238 Discussions

How to make DLL routines thread safe?

DavidWhite
Valued Contributor II
2,150 Views
I have a number of routines in a Fortran DLL which is now going to be called from a multi-threaded C++ program. I have no control on the number of threads or which actual routines are called.

What do I need to do to make them thread safe?

I have identified a number of arrays which were defined in a module, but which could be changed by various routines. Taking them out of the modules, and leaving only parameters in the modules seemed to increase the number of threads which a test program reported having incorrect results.

Should I copy arguments to local variables in each routine? What else do I need to look for?

Thanks,


David
0 Kudos
9 Replies
Arjen_Markus
Honored Contributor II
2,150 Views

The main problem is that variables might be inadvertently accessed by different threads
at the same time. That can happen if:
- a variable is defined in a module, rather than as a local, automaticvariable in a routine
- a local variable in a routine has the SAVE attribute (then it is no longer automatic) - note
that a local variable that is given a value in its declaration or via a DATA statement has
that attribute implicitly

Arguments are safe - they belong to the caller, so it is the caller's responsibility to make
sure everything is all right. There is no need to copy them.

Here is a small example:

module mymodule
integer :: unsafe_ var ! Accessible in any thread that uses the module
contains
subroutine mysub( arg1 )
integer :: arg1 ! Dummy
integer :: safe_local1 !Automatic
integer :: unsafe_local = 1 ! Implicit SAVE statement
...
end subroutine mysub
end module mymodule

Regards,

Arjen

0 Kudos
DavidWhite
Valued Contributor II
2,150 Views
Thanks Arjen.

I moved all of the working variables to each routine, none of these had initialisation, so should be automatic. Only variables in the module are parameters.

However, this still did not work. In debug mode, I had up to 80% error rate in the threaded application, and 7% in release mode.

I have now added RECURSIVE to all my subroutines, and this appears to have solved the problem.

Regards,

David
0 Kudos
DavidWhite
Valued Contributor II
2,150 Views
Arjen,

Just need to add one more thing - local arrays are STATIC, so complete example would be


module mymodule
integer :: unsafe_ var ! Accessible in any thread that uses the module
contains
subroutine mysub( arg1 )
integer :: arg1 ! Dummy
integer :: safe_local1 !Automatic
integer :: unsafe_local = 1 ! Implicit SAVE statement
integer, dimension(5), automatic :: safe_array1
...
end subroutine mysub
end module mymodule
0 Kudos
IanH
Honored Contributor III
2,150 Views
Check out the /recursive and /automatic command line options and save your fingers some typing.

(Note that automatic in the fortran standard refers to a slightly different concept - anything with a non-constant characteristic (kind, length or size), it so happens that a common implementation for automatic objects is to make them stack based. Then again, I think Intel's automatic keyword (an extension) harks back to the implementation side of things.)
0 Kudos
Arjen_Markus
Honored Contributor II
2,150 Views
Hm, I thought that the default for Intel Fortran was to make such arrays automatic, in contrast to Compaq
Visual Fortran that definitely made them local unless you instructed it to do otherwise.

With Ian's suggestions this should indeed work. If you do not want to rely on compiler options (or compiler
extensions), then use the "recursive" keyword for all subroutines and functions. That will force the compiler
to make every local variable (scalar or otherwise) to be non-static (unless the SAVE attribute comes into
play).

Regards,

Arjen
0 Kudos
Steven_L_Intel1
Employee
2,150 Views
Arjen has the right idea - use the RECURSIVE keyword. But it is insufficient to add AUTOMATIC to arrays as this does not affect descriptors the compiled code uses. The RECURSIVE keyword will do all the right things.
0 Kudos
Anna_B_1
Beginner
2,150 Views

But if one creates the threads with MPI or another library such that each thread uses different memory, is it unnessecary to make the Fortran code thread safe then? (The Fortran "global variables" are not shared by the threads?)

0 Kudos
TimP
Honored Contributor III
2,150 Views

RECURSIVE declarations aren't needed for MPI without threading or recursion, but combinations of MPI with threading are increasingly widespread.
 

0 Kudos
Steven_L_Intel1
Employee
2,150 Views

Use of MPI does not involve threads - each MPI "rank" is in its own process with independent address space. But it is worthwhile coding for thread safety regardless.

Adding the RECURSIVE keyword will go a long way towards this, but you have to watch out for variables that get implicit SAVE semantics due to initialization.

0 Kudos
Reply