The .NET framework supports threads. This means that it is possible to have a
program that is effectively doing several things at the same time.
Multiple threads can be very useful but programs with threads
are usually much more difficult to debug. Consequently they should be
When a program contains two or more threads its
execution is analogous to the situation where multiple
programs are running simultaneously. However the various threads share the
same address space. On a typical single processor machine each active thread
runs for a short period of time until it is swapped out to permit another
thread to run. This can be useful, for example, when you want
to control a GUI interface or access data over the Internet whilst a long
numeric calculation is proceeding. Using threads in such circumstances can
make your program much more responsive to user interaction.
Threading is also the key to exploiting the power of multi-processor machines.
When a machine has several processors (typically two) several threads
can literally run simultaneously - true parallel processing. This
happens automatically if several processors are available.
Although it is possible to create and start a thread using calls to the .NET
framework, FTN95 provides a shortcut:
SUB is the routine in your code that is called to start the thread.
SUB is presented in the form of a subroutine that accepts one integer
argument. The value that is used in the resulting call to SUB is the value
of ICODE. Thus you can choose to start several threads using the same
subroutine but with different values of ICODE to distinguish the cases.
Here is a simple example of code to start a thread:
PRINT*,'Finishing main program.'
PRINT*,'In foo ',m
In this example the two PRINT statements may execute in either order and this
will typically vary from one run to another. This reflects the fact that the
threads in your program run asynchronously. This program will continue to
execute until all threads have terminated.
The first call to CREATE_THREAD@ in a program enables re-entrant
Fortran I/O so that I/O on one thread does not cause a fault when it coincides
with I/O on another thread. If you use I/O in several threads you must use
different unit numbers unless you use the LOCK statement to prevent a swap
before the I/O statement has finished. For example:
If you use threads you must design your program in such a way
that each thread can run independently. Moreover, it is important to note
that a program that contain multiple threads
might contain bugs that only show
up intermittently (because the way in which threads interact can vary
from one run to another). For this reason programs with multiple
threads can be very hard to debug.
As an alternative to CREATE_THREAD@, the FTN95 routine CREATE_THREAD1@
provides for an additional argument that returns a handle for the thread.
This handle can be used in calls to System.Threading.Thread methods and
these enable the user to interact with a thread that is running. For
example, a call can be made to System.Threading.Thread.Join in order to
wait for a thread to terminate.
Here is the form of the interface for CREATE_THREAD1@:
System.Threading.Thread.Join is a static method (see
Calling .NET methods from Fortran) so it can be called using, for
. . .
Here is an example that illustrates the use of CREATE_THREAD1@:
!Do some processing...
PRINT*,'Finishing main program.'
PRINT*,'In foo ',m
In this example the output from the subroutine will appear before that from
the main program.
Other thread methods are provided in addition to Join. These are described in
the .NET documentation.
When using the .NET framework there are certain
overheads that are incurred by multi-threaded programs. Because of this
the linker DBK_LINK or DBK_LINK2 assumes by default that the code does
not use multi-threading. The DBK_LINK or DBK_LINK2 command line option
/MULTI_THREADED must be used to inform the linker that the code makes
calls to either CREATE_THREAD@ or CREATE_THREAD1@. The same option can
be employed with FTN95 when it is used with /LINK. If you do not
use this option then an exception will be raised at runtime when either of
these routines is called. You must also use the
option /MULTI_THREADED when you create a thread directly using
System.Threading.Thread methods, otherwise the resulting behaviour is
undefined. This option is also required when a library is created if
it contains a routine that is called on more than one thread.
If you need to start a number of threads you can used the /STACK
option to reduce the default stack size per thread. /STACK is a DBK_LINK
command line switch. It is also available on the FTN95 command line for
use with /LINK or /LGO. The given (decimal) size of the
stack refers to the number of bytes of virtual storage (i.e. address
space) allocated to a single threaded program and to each thread of a
By default the stack size is set to 96 megabytes (this is over 100
million bytes; the default KIND for an INTEGER value and a REAL
value each occupy 4 bytes). This large value is adequate for most (single
threaded) Fortran programs even when they contain large local arrays (these are
allocated on the stack). However, for multiple threads, this amount
of memory is allocated for each thread and the default stack size can be
unduly large. Conversely, single-threaded programs that contain
exceptionally large local arrays may require a stack size that
is larger than the default. You will find, however, that stack overflow
exceptions are currently not well reported by the .NET framework.