当作为共享库加载时,Fortran模块可分配数组何时超出范围? [英] When do Fortran module allocatable arrays go out of scope when loaded as a shared library?

查看:70
本文介绍了当作为共享库加载时,Fortran模块可分配数组何时超出范围?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

作为更复杂的优化问题的一部分,我正在从R调用fortran子例程.当前,该子例程是自包含的-具有当前参数值的输入以及功能评估和梯度项的输出.现在,我希望将可分配数组初始化为共享模块变量(优化之前),该变量将在优化过程中由子例程使用(但不可修改).

I am calling a fortran subroutine from R as part of a more complex optimization problem. Currently, the subroutine is self-contained -- with an input of current parameter values and an output of function evaluation and gradient terms. I now wish to initialize an allocatable array as a shared module variable (prior to the optimization) that will be used (but not modified) by the subroutine during optimization.

在这种情况下,共享可分配数组何时会超出范围或被删除?

In this context, when would the shared allocatable array go out of scope or be deleted?

对于Fortran Wikibook的内存管理部分的幼稚阅读表明模块变量应该保持(可能甚至在执行程序之后).

A naive reading of the memory management section of Fortran wikibook suggests that module variables should persist (possibly even after a program has been executed).

我阅读过的来源当超出范围时,可分配数组将自动释放.变量是否也会发生这种情况?何时发生?

A number of sources I've read indicate that an allocatable array will be deallocated automatically when it goes out of scope. Does this happen for module variables as well and when would this happen?

我找到了数量. /stackoverflow.com/questions/11837616/fortran-allocatable-array-lifetime>相关

I've found a number of related questions but I haven't been able to place them in context of both module variables and shared library loading.

fortran模块的最小示例.分配的数组在fortran程序中按预期方式工作.实际上,init()eval()都将由R函数(init_wrap()eval_wrap())包装并从R中调用.我想确认分配的变量y保证不会超出范围或在test_module作为共享库加载时被删除.

A minimal example of the fortran module. The allocated array works as expected in a fortran program. In practice, both init() and eval() will be wrapped by R functions (init_wrap() and eval_wrap()) and called from R. I want to confirm that the allocated variable y is guaranteed not to go out of scope or get deleted while test_module is loaded as a shared library.

module test_module

  double precision, allocatable, dimension(:,:) :: y

  contains

    subroutine init() bind(C, name = "init_")

      if (.not. allocated(y) ) then
        allocate(y(1,1))
      end if

      y = 1
    end subroutine init

    subroutine eval(x, z) bind(C, name = "eval_")

      double precision, intent(in) :: x
      double precision, intent(out) :: z

      z = x + y(1,1)

    end subroutine eval

end module test_module

! Program added for testing purposes only, 
! module is used as shared library
program test_program

   use test_module

   double precision :: x, z

   ! Initialize allocatable array
   call init()

   ! Use allocatable array during optimization
   x = 1
   call eval(x, z)

   x = 2
   call eval(x, z)

   print *, z

end program test_program

我已经在github上创建了一个框架包,用于模拟我如何使用fortran代码: https: //github.com/ssokolen/fortran.test

I've created a skeleton package on github that models how I'm using fortran code: https://github.com/ssokolen/fortran.test

下面的R代码按我需要的方式工作(分配的数组在eval_wrap()调用之间保留其值),但是我仍然希望在何时分配的模块变量超出范围时得到明确的答案作为共享库加载(或说明没有任何常规行为的答案).

The following R code works as I need it to (the allocated array keeps its value between eval_wrap() calls), but I'm still hoping to get a definitive answer on when an allocated module variable would go out of scope when loaded as a shared library (or an answer that states that there is no general behaviour).

library(devtools)
install_github('ssokolen/fortran.test')
library(fortran.test)
init_wrap()
eval_wrap(1)
eval_wrap(2)

推荐答案

动态加载的库超出了Fortran标准.整个处理器"所指示的情况是什么,它是Fortran编译器,操作系统,链接器等的复杂结构.

Dynamically loaded libraries are beyond Fortran standard. What happens indicated by the whole "processor" which is the complex of Fortran compiler, operating system, linker and so on.

在Linux和其他POSIX操作系统中,如果从内存中卸载该库,它将超出范围.这个简单的测试案例表明:

In Linux and other POSIX operating systems, if you unload the library from memory, it will go out of scope. This simple test case demonstrates that:

module test_module

  double precision, allocatable, dimension(:,:) :: y

  contains

    subroutine init() bind(C, name = "init_")
      print *, "init_"
      if (.not. allocated(y) ) then
        allocate(y(1,1))
      end if

      y = 1
    end subroutine init

    subroutine eval(x, z) bind(C, name = "eval_")

      double precision, intent(in) :: x
      double precision, intent(out) :: z

      if (.not. allocated(y) ) error stop("not allocated!")
      z = x + y(1,1)
      print*, "success"
    end subroutine eval

end module test_module

然后C调用该库:

#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>

int main(){

  void *handle = dlopen("/home/lada/f/testy/stackoverflow/dltest.so",RTLD_NOW);

  void (*init_)() = (void (*)())dlsym(handle, "init_");
  init_();

  double x=0,y=0;
  void (*eval_)(double x, double z) = (void (*)())dlsym(handle, "eval_");      
  eval_(x, y);

  dlclose(handle);
  handle = dlopen("./dltest.so",RTLD_NOW);

  eval_ = (void (*)())dlsym(handle, "eval_");
  eval_(x, y);

  return 0;

}

然后运行:

> gfortran -shared -fPIC -o dltest.so dltest.f90
> gcc -ggdb  dltest.c -ldl
> ./a.out 
 init_
 success
ERROR STOP not allocated!

dlclose()dlopen()之后不再分配数组.您必须确保R不会从内存中卸载库.

The array is no longer allocated after dlclose() and dlopen(). You must make sure that R will not unload the library from memory.

这篇关于当作为共享库加载时,Fortran模块可分配数组何时超出范围?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆