将 OpenMP 和 Intel Visual Fortran 与 Windows GetProcAddress 结合使用

Using OpenMP and Intel Visual Fortran with Windows GetProcAddress

提问人:A_Weiss 提问时间:7/29/2020 更新时间:7/29/2020 访问量:223

问:

我正在通过 Microsoft Visual Studio 2015 IDE 使用英特尔 Fortran 编译器 15.0。我正在学习 OpenMP 以(最终)并行运行我的代码部分。我的代码将需要从 .dll 加载子例程。我有以下程序,它加载带有 HelloWorld 子例程的 .dll 并调用该子例程;下面的代码在一个简单的控制台应用程序中执行得很好。

program LoadThisLibrary
 
Use DFWIN
Use DFLIB

implicit none

!Variable declarations
Character (len=8) SubName

!Pointer declarations
 Integer i !not used but must be declared as part of a POINTER declaration.
 Pointer (p,i)
 Integer(INT_PTR_KIND()) paa(100)  !declares an integer array that will contain pointer addresses
 
!Declare an interface for MySub                                            
 Interface
   Subroutine MySub
   End Subroutine MySub
 End Interface
 
! Declare a pointer/pointee structure - this allows us to later "call" a pointer by its pointee (subroutine) name. 
! This is a CVF function, not "pure fortran"  
 Pointer(SubNum,MySub) 
 
!Load the dll that contains the subroutine we want to run
p = LoadLibrary("HelloDLL.dll"C) 
 
!Name the subroutine we wish to call from that dll
SubName = TRIM("HELLOSUB")//CHAR(0)

!Get a pointer to the subroutine we want and store it in the pointer array
paa(1) = GetProcAddress(p,SubName)

!set a POINTER to the subroutine's memory location
SubNum = paa(1) 

!Call the subroutine loaded from the dll
 Call MySub

end

这是“HelloDLL.dll”的代码

subroutine HelloSub

  ! Expose subroutine HelloSub to users of this DLL
  !
  !DEC$ATTRIBUTES DLLEXPORT :: HelloSub

  ! Variables
  character variable
  
  ! Body of HelloSub 
  print *, "Congratulations! You have run a dll subroutine. You are the best. I am in awe of your brilliance. You have triumphed in the face of adversity. "
  READ(*,*) variable

end subroutine HelloSub

为了启用 OpenMP 指令,我转到 Project -> Console Properties(在我的 IDE 中),然后转到 Fortran -> Language,并将 “Process OpenMP Directives” 设置为 “Generate Parallel Code (/Qopenmp)”。当我这样做时,没有别的,不对我的源代码进行任何更改,我的代码不再运行。具体来说,我发现 LoadLibrary 仍然可以找到 HelloDLL.dll 的地址,但 GetProcAddress 调用返回一个 null 值 (0)。我是否在主程序代码中包含 USE OMP_LIB或使用任何 OpenMP 指令或函数似乎并不重要。我尝试重命名 paa() 数组,甚至将地址保存为一个普通整数 - 似乎没有任何效果。

我将不胜感激任何建议或见解。显然,启用 OpenMP 不仅仅是允许访问 OpenMP 的功能,我只是无法弄清楚为什么它会对 GetProcAddress 产生任何影响。如果可以的话,请帮忙!提前非常感谢。

DLL fortran openmp getprocaddress

评论

0赞 Vladimir F Героям слава 7/29/2020
我强烈建议你不要使用克雷指针,它们从来都不是标准的,而且在实践中确实已经过时了。Fortran 具有足够的标准功能。
0赞 A_Weiss 7/29/2020
感谢您的反馈。我正在使用继承的代码,并且不得不谷歌“Cray 指针”是什么。如果您对 Fortran 中 Cray 指针的替代品有任何建议,我很乐意听到它们,否则我会继续自己挖掘。
0赞 Vladimir F Героям слава 7/30/2020
标准类型(来自 is_c_binding)模块:c_ptr 和 c_funptr 以及可用于使用它们的过程(c_loc、c_funloc、c_f_pointer c_f_procpointer) gcc.gnu.org/onlinedocs/gfortran/Working-with-Pointers.html 使用 transfer() 应该可以在 Cray 指针和c_ptr或c_funptr之间进行转换。
0赞 A_Weiss 7/31/2020
感谢您的建议!我在谷歌上搜索过的其他代码中看到了这些,但并不真正知道如何实现它们。谢谢你的建议。

答:

1赞 IanH 7/29/2020 #1

以 null 结尾的子例程名称 (8+1 = 9) 比变量 (8) 的长度长。当表达式 assigning to 中存在 null 终止符时,它将作为赋值的一部分被截断(不能将 9 个字符放入 8 个字符中)。SubNameSubName

null 终止符是否恰好紧跟在存储 for 之后取决于内存中变量的布局(以及可能的随机机会)。如果没有 null 终止符,传递给 GetProcAddress 的名称将是无意义的。内存中变量的布局是会改变的。SubName/Qopenmp

更正 的长度。请考虑使用可分配的字符标量,使代码能够适应过程名称长度的后续更改。SubName

(存在其他风格或可移植性问题,但它们更主观。

评论

0赞 A_Weiss 7/29/2020
非常感谢!我将 SubName 的字符长度从 8 和 9 更改为 8 和 9,现在启用 /Qopenmp 后运行良好。再次感谢你,这让我发疯了。