【问题标题】:Fortran Unhandled Exception (msvcr100d.dll)Fortran 未处理的异常 (msvcr100d.dll)
【发布时间】:2013-03-28 12:06:09
【问题描述】:

我在退出程序时遇到了这个未处理的异常:

Unhandled exception at 0x102fe274 (msvcr100d.dll) in Parameters.exe: 0xC0000005: Access violation reading location 0x00000005.

调试器在此行的名为 crtdll.c 的模块中停止:

onexitbegin_new = (_PVFV *) DecodePointer(__onexitbegin);

调用堆栈的第一行写着:

msvcr100d.dll!__clean_type_info_names_internal(__type_info_node * p_type_info_root_node=0x04a6506c) 第 359 行 + 0x3 字节 C++

程序会一直保留在内存中,直到我关闭 IDE。

我更习惯于使用托管语言进行开发,所以我认为我的代码维护有问题。代码本身读取内存映射文件并将其与指针关联:

SUBROUTINE READ_MMF ()
  USE IFWIN
  USE, INTRINSIC :: iso_c_binding
  USE, INTRINSIC :: iso_fortran_env 

  INTEGER(HANDLE) file_mapping_handle
  INTEGER(LPVOID) memory_location
  TYPE(C_PTR) memory_location_cptr
  INTEGER memory_size  
  INTEGER (HANDLE) file_map      
  CHARACTER(5)                   :: map_name 
  TYPE(C_PTR)                    :: cdata
  integer                        :: n = 3
  integer(4), POINTER            :: A, C
  real(8), POINTER               :: B

  TYPE STRUCT
    integer(4) :: A 
    real(8)    :: B
    integer(4) :: C
  END TYPE STRUCT
  TYPE(STRUCT), pointer :: STRUCT_PTR

  memory_size = 100000
  map_name = 'myMMF'

  file_map = CreateFileMapping(INVALID_HANDLE_VALUE,
 + NULL,
 + PAGE_READWRITE,
 + 0,
 + memory_size,
 + map_name // C_NULL_CHAR )  

  memory_location = MapViewOfFile(file_map,
 +IOR(FILE_MAP_WRITE, FILE_MAP_READ),
 + 0, 0, 0 )          

  cdata = TRANSFER(memory_location, memory_location_cptr)
  call c_f_pointer(cdata, STRUCT_PTR, [n]) 

  A => STRUCT_PTR%A
  B => STRUCT_PTR%B
  C => STRUCT_PTR%C

  RETURN
  END

当我用完 c 指针后,我应该释放它们吗?我调查了一下,但看不到我在 Fortran 中是如何做到的......

感谢您的帮助!

【问题讨论】:

  • 释放内存会更干净,但是当程序退出时操作系统会为你做这件事。 Fortran 无法释放在 C 中分配的内存……您将为此使用 C 例程。此外,integer(4)real(8) 可能是也可能不是 4 和 8 字节数。它们是种类 4 和种类 8,它们依赖于处理器(编译器)。见stackoverflow.com/questions/3170239/…stackoverflow.com/questions/10520819/what-does-real8-mean
  • P.S.由于您使用的是iso_fortran_env,因此您可以使用一种可靠且便携的方式来请求特定的尺寸编号。对于 4 字节整数:integer (int32);对于 8 字节实数:real (real64)。至少如果您的编译器具有 ISO Fortran 环境的 Fortran 2008 版本。
  • M.S.B,感谢您对字节大小的评论。我使用英特尔编译器,但我不知道我可以使用 (int32) 等来控制数据类型的字节大小。我将继续使用它。

标签: pointers memory-management fortran unhandled-exception fortran-iso-c-binding


【解决方案1】:

访问冲突的性质(在运行时库清理期间)表明您的程序正在以某种方式破坏内存。有许多编程错误会导致这种情况 - 并且负责的错误或错误可能出现在您的程序中的任何地方。通常的“在启用所有诊断和调试选项的情况下编译和运行”方法可能有助于识别这些。

也就是说,显示的代码示例中存在编程错误。 ISO_C_BINDING 内部模块中的 C_F_POINTER 过程可以对标量或数组 Fortran 指针(第二个参数)进行操作。如果 Fortran 指针是标量,则第三个“shape”参数不得存在(如果 Fortran 指针是数组,则必须存在)。

您的代码打破了这一要求——代码中的 Fortran 指针 STRUCT_PTR 是一个标量,但您提供了第三个形状参数(如 [n])。这个错误很可能会导致内存损坏 - 通常 C_F_POINTER 的实现会尝试在内存中填充 Fortran 指针的描述符,并且指向数组的指针的描述符可能与指向标量的指针非常不同.

随后对STRUCT_PTR 的引用可能会进一步恶化。

虽然标准不要求诊断这种情况,但我有点惊讶编译器没有发出诊断(假设您的示例代码是您实际正在编译的)。如果您将此情况报告给编译器的供应商(英特尔,大概是 IFWIN 等),我怀疑他们会将其视为编译器的缺陷。

要释放与文件映射相关的内存,请使用 UnmapViewOfFile 和 CloseHandle API。要使用这些,您应该“存储”(您的程序需要以某种方式记住)MapViewOfFile 返回的基地址(memory_location,也可以通过在上述问题解决后在STRUCT_PTR 上调用 C_LOC 来获得),以及CreateFileMapping 返回的映射句柄 (file_map);分别。

【讨论】:

  • Ian,感谢您的详细回答 - 我现在对正在发生的事情有了更好的了解。我目前正在尝试研究如何使用您提到的 UnmapViewOfFile 和 CloseHandle API。您能否通过“存储”数据来扩展您的意思?我注意到释放视图 (UnmapViewOfFile) 会导致变量 (a,b,c) 变得未定义。
【解决方案2】:

我只用 Cray 指针做过这个:不是用 ISO 绑定,我知道它可以用 Cray 指针。

您没有说的是这是第一次还是第二次调用例程时发生。如果多次调用,则编码存在问题,即 Create/OpenFileMapping 只能调用一次以获取句柄。

你不需要释放内存,因为内存不是你要释放的:你需要调用 UnmapViewOfFile(memory_location)。调用此方法后,memory_location、memory_location_cptr 和可能的 cdata 将不再有效。

这种工作方式是使用两个或多个程序:

一个程序调用 CreateFileMapping,其他程序调用 OpenFileMapping 来获取数据的句柄。这只需要在程序开始时调用一次:而不是每次您需要访问文件时。多次调用 Create/OpenFileMapping 而没有相应的关闭可能会导致崩溃。

然后他们调用 MapViewOfFile 将文件映射到内存中。请注意,一次只有一个程序可以执行此操作。当程序处理完内存文件后,它会调用 UnmapViewOfFile。另一个程序现在可以访问该文件。有一个阻塞机制。如果不调用 UnmapViewOfFile,其他使用 MapViewOfFile 的程序会被阻塞。

完成后,在 Create/OpenFileMapping 创建的句柄上调用 close。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-19
    • 2018-06-21
    • 1970-01-01
    • 1970-01-01
    • 2011-01-16
    相关资源
    最近更新 更多