要放置一些背景上下文,我需要一个线程安全随机数生成器,以用于需要跨编译器和跨平台兼容的多线程Fortran代码。实现此目标的最佳方法是遵守语言标准。因此,我想将C ++ 11随机数生成器包装在一个可以从fortran中调用的函数中,以便每个线程有一个随机数生成器,每个线程都有它自己的状态对象。
所以我创建了一个带有3个C函数绑定的小型C ++类。
#include <random>
#include <iostream>
class random {
std::mt19937_64 engine;
std::uniform_real_distribution<double> dist;
public:
random(uint64_t seed) : engine(seed), dist(0.0, 1.0) {};
double get_number() {
return dist(engine);
}
};
extern "C" {
void *random_construct(int seed) {
return new class random(static_cast<uint64_t> (seed));
}
double random_get_number(void *r) {
return static_cast<class random *> (r)->get_number();
}
void random_destroy(void *r) {
delete static_cast<class random *> (r);
}
}
Fortran界面
MODULE random
USE, INTRINSIC :: iso_c_binding
IMPLICIT NONE
INTERFACE
TYPE (C_PTR) FUNCTION random_construct(seed) &
& BIND(C, NAME='random_construct')
USE, INTRINSIC :: iso_c_binding
IMPLICIT NONE
INTEGER (C_INT), VALUE :: seed
END FUNCTION
END INTERFACE
INTERFACE
REAL (C_DOUBLE) FUNCTION random_get_number(r) &
& BIND(C, NAME='random_get_number')
USE, INTRINSIC :: iso_c_binding
IMPLICIT NONE
TYPE (C_PTR), VALUE :: r
END FUNCTION
END INTERFACE
INTERFACE
SUBROUTINE random_destroy(r) &
& BIND(C, NAME='random_destroy')
USE, INTRINSIC :: iso_c_binding
IMPLICIT NONE
TYPE (C_PTR), VALUE :: r
END SUBROUTINE
END INTERFACE
END MODULE
还有一个小程序对此进行测试。
PROGRAM random_test
USE random
IMPLICIT NONE
TYPE (C_PTR) :: rand_object
INTEGER :: count
CALL SYSTEM_CLOCK(count)
rand_object = random_construct(count)
WRITE(*,*) random_get_number(rand_object)
CALL random_destroy(rand_object)
WRITE(*,*) random_get_number(rand_object) ! Expected to segfault.
END PROGRAM
运行此命令表明我的销毁功能似乎无法正常工作,因为我的销毁功能之后的调用仍在生成随机数。
如果我将测试程序更改为
PROGRAM random_test
USE random
IMPLICIT NONE
TYPE (C_PTR), ALLOCATABLE :: rand_object
INTEGER :: count
CALL SYSTEM_CLOCK(count)
rand_object = random_construct(count)
WRITE(*,*) random_get_number(rand_object)
DEALLOCATE (rand_object)
WRITE(*,*) random_get_number(rand_object)
END PROGRAM
现在,它会产生我预期的行为,并且在DEALLOCATE之后会出现段错误。现在我的直觉反应说这应该行不通,因为我永远不会尝试用一种语言分配内存,而用另一种语言取消分配内存。但是,有什么理由不应该这样做吗? C ++对象是POD类型,因此其内存应该是连续的。然后,只要Fortran具有正确的内存地址,它就可以轻松地对其进行分配。这里有我想念的东西吗?