Search code examples
c#fortranpinvokegfortran

Simultaneous calls of a method in a fortran dll with module variables, in C#


I'm trying to make calls of a Fortran method simultaneously in different threads. The executions are completely independent from each other and the main thread. The problem is that using module variables means that the variables are made global by the dll, meaning the two calls would use it, thus instacrashing the program, and so it happens. This is my interpretation, based on this answer of Bálint Aradi.

C#

    static void Main(string[] args)
    {
        RunTwiceSync();//WORKS
        RunTwiceAsync();//INSTACRASH
    }

    private static void RunTwiceSync()
    {
        TestMyArray();
        TestMyArray();
    }

    private static void RunTwiceAsync()
    {
        ThreadStart ts = new ThreadStart(() =>
        {
            TestMyArray();
        });
        Thread t = new Thread(ts);
        t.Start();
        TestMyArray();
    }

    private static void TestMyArray()
    {
        Console.WriteLine("START");
        int size = 52;
        float[] myarray = new float[size];
        sub_(ref size, myarray);
        Console.WriteLine(myarray.Select(x => x.ToString()).Aggregate((x, y) => x + ";" + y));
        Console.ReadLine();
    }


    [DllImport("FortranArraySimpleTest.dll", CallingConvention = CallingConvention.Cdecl)]
    static extern void sub_(ref int size, float[] myarray);

FORTRAN

 !DEC$ ATTRIBUTES DLLEXPORT::ingammaextern
subroutine sub(size, myarray)
    use module1   ! * REMOVING MODULE USAGE FIXES THE PROBLEM
  implicit none
INTEGER  :: size
integer :: assignme
REAL, dimension(1:size) :: myarray

assignme = size
allocate(alocarray(1:assignme))
deallocate(alocarray)
end subroutine
! ************************************begin another file***********
      MODULE module1
      IMPLICIT NONE


real, dimension(:), allocatable :: alocarray
      END MODULE module1

This solution, the removal of modules, is extremely cumbersome and a maintenance major headache, due to the code which made me post the question being very large.

Environment: GNU Fortran Compiler, windows 7 64bits, CodeBlocks for fortran, VS2012, i didn't change any compiler options.

Any ideas?

Thank you for your time


Solution

  • What can be done is to change the module for a derived type, which is then passed with every call

    module orig
      use whatever
    
      interfaces
    
      small types
    
      variables
    
    contains
    
      procedures
    
    end module
    

    to

    module state_class
    
      use whatever
    
      interfaces
    
      small types
    
      shared variables
    
      type state
        non shared variables
      contains
        procedure :: the procedures
        (not obligatory)
      end type
    
    contains
    
      procedures changed to accept one additional argument:
      a passed dummy argument class(state)
      or just a regular dummy argument type(state)
    
    end module
    

    Every thread has own state class instance and passes it explicitly or as a passed dummy argument.