Fortran プログラムで奇妙な問題が発生しています。私のアプリケーションに関する詳細は次のとおりです。
ALLOCATABLE
データ構造を使用して情報を保持double の配列へのポインターを返す C++ dll とのインターフェイス。組み込みメソッドを使用して、C++ 配列ポインターを Fortran ポインターに変換します。
c_f_pointer
XML ファイルから読み取り、出力を XML ファイルと 2 つのテキスト ファイルに書き込みます。
Fortran とSimply Fortran IDEgfortran
をコンパイルするために使用しています。C++ 側では、and code::Blocksを使用しています。アプリケーションは問題なくビルドされ、デバッグ モードで実行されます。gcc
しかし、アプリケーションの実行可能ファイルをダブルクリックして、そのような起動が何をするかを確認すると、応答しませんでした。タスク マネージャーに移動して、プログラムを強制終了する必要がありました。私は何度も試しましたが、そのたびにそれが起こりました。アプリケーションとgmon.outによって作成された出力ファイルを削除し、実行可能ファイルをダブルクリックすると、プログラムが再び実行されます。
数回実行される可能性があり、ランダムにフリーズします。次に、上記のプロセスを繰り返すと、アプリケーションが復活することがあります。ここで何が問題なのか本当に迷っています。それは悪いメモリ管理のプロセスですか?C++ ポインタと Fortran ポインタの処理方法と関係がありますか?
デバッグ版に問題があるのではないかと思ったので、デバッグ変数を含まないオプションにプロジェクトを変更しましたが、問題は解決しません。
必要に応じて、問題を示す簡単なプログラムを作成することができます。
アイデア/ヘルプ/提案は大歓迎です。
*新情報
コメントで尋ねられたように、小さな実用的な例を作成しようとしましたが、その間に問題を解決しました。しかし、それが解決した理由はわかりません。よりよく理解するために、CPP ヘッダーとソース ファイルをここに置きます。
DLL.h
#ifndef DLL_H_INCLUDED
#define DLL_H_INCLUDED
#include <windows.h>
#include <stdio.h>
#include <math.h>
/* To use this exported function of dll, include this header
* in your project.
*/
#ifdef BUILD_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
#endif
extern "C"
{
double DLL_EXPORT __cdecl *Function1(int InputCombination, double Input1, double Input2, double Pressure);
double DLL_EXPORT __cdecl Function2(double DBTemperature, double WBTemperature, double Pressure);
double DLL_EXPORT __cdecl Function3(double DBTemperature, double WBTemperature, double Pressure);
double DLL_EXPORT __cdecl Function4(double DBTemperature, double WBTemperature, double Pressure);
double DLL_EXPORT __cdecl Function5(double DBTemperature, double WBTemperature, double Pressure);
double DLL_EXPORT __cdecl Function6(double DBTemperature, double WBTemperature, double Pressure);
double DLL_EXPORT __cdecl Function7(double DBTemperature, double WBTemperature, double Pressure);
double DLL_EXPORT __cdecl Function8(double DBTemperature, double RelHumidity, double Pressure,int LoadLibraryFlag=1);
double DLL_EXPORT __cdecl Function9(double DBTemperature, double HumRatio, double Pressure);
double DLL_EXPORT __cdecl Function10(double DBTemperature, double Enthalpy, double Pressure);
}
double DB,WB,HR,RH,DP,SpVOL,ENTH;
const double CtoK = 273.15;
const double KtoC = -273.15;
#endif // DLL_H_INCLUDED
DLL.cpp
#include "DLL.h"
typedef double (__cdecl *fp_BisectionRootFinderTYPE) (double, double, double, double, double*, int, double(*)(double,double*));
extern fp_BisectionRootFinderTYPE BisectionRootFinder;
fp_BisectionRootFinderTYPE BisectionRootFinder;
double DLL_EXPORT __cdecl *CalcAirProperties(int InputCombination, double Input1, double Input2, double Pressure)
{
/*
Input Combination:
1: Given DB [C], WB [C] and Pressure [kPa]
2: Given DB [C], RH and Pressure [kPa]
3: Given DB [C], phi and Pressure [kPa]
4: Given DB [C], DP [C] and Pressure [kPa]
*/
double *AirProperties = new double[7];
/*
Air Properties:
[0]: Dry bulb Temperature [C]
[1]: Wet bulb temperature [C]
[2]: Humidity ratio []
[3]: Relative Humidity []
[4]: Dew point Temperature [C]
[5]: Specific Volume [m3/kg_da]
[6]: Enthalpy [kJ/kg_da]
*/
HINSTANCE MathRoutinesInstance;
MathRoutinesInstance = LoadLibrary("./MathRoutines.dll");
BisectionRootFinder = (fp_BisectionRootFinderTYPE) GetProcAddress(MathRoutinesInstance,"BisectionRootFinder");
if(InputCombination == 1)
{
DB = Input1;
WB = Input2;
HR = Function2(DB,WB,Pressure);
RH = Function3(DB,WB,Pressure);
DP = Function4(DB,WB,Pressure);
SpVOL = Function5(DB,WB,Pressure);
ENTH = Function6(DB,WB,Pressure);
}
else if(InputCombination == 2)
{
DB = Input1;
RH = Input2;
WB = Function8(DB,RH,Pressure,1);
HR = Function2(DB,WB,Pressure);
DP = Function4(DB,WB,Pressure);
SpVOL = Function5(DB,WB,Pressure);
ENTH = Function6(DB,WB,Pressure);
}
else if(InputCombination == 3)
{
DB = Input1;
HR = Input2;
RH = Function7(DB,HR,Pressure);
WB = Function8(DB,RH,Pressure,1);
DP = Function4(DB,WB,Pressure);
SpVOL = Function5(DB,WB,Pressure);
ENTH = Function6(DB,WB,Pressure);
}
else if(InputCombination == 4)
{
DB = Input1;
ENTH = Input2;
HR = HumRatfn_DB_Enthalpy_Pressure(DB,ENTH,Pressure);
RH = RelHumidityfn_DB_HumRat_Pressure(DB,HR,Pressure);
WB = WBTempfn_DB_RH_Pressure(DB,RH,Pressure,1);
DP = Function4(DB,WB,Pressure);
SpVOL = Function5(DB,WB,Pressure);
}
else
{
DB = Input1; // + KtoC
WB = Input2; // + KtoC
HR = HumRatfn_DB_WB_Pressure(DB,WB,Pressure);
RH = RelHumidityfn_DB_WB_Pressure(DB,WB,Pressure);
DP = DewPointTempfn_DB_WB_Pressure(DB,WB,Pressure);
SpVOL = SpecVolumefn_DB_WB_Pressure(DB,WB,Pressure);
ENTH = Enthalpyfn_DB_WB_Pressure(DB,WB,Pressure);
}
AirProperties[0] = DB;
AirProperties[1] = WB;
AirProperties[2] = HR;
AirProperties[3] = RH;
AirProperties[4] = DP;
AirProperties[5] = SpVOL;
AirProperties[6] = ENTH;
FreeLibrary(MathRoutinesInstance);
return AirProperties;
}
double DLL_EXPORT __cdecl Function8(double DBTemperature, double RelHumidity, double Pressure,int LoadLibraryFlag) //
{
/*
Input:
DBTemperature - Dry bulb Temperature [C]
RelHumidity - Relative Humidity [-]
Pressure - Barometric Pressure [kPa]
Output:
WBTemperature- Wet bulb Temperature [C]
Reference:
ASHRAE Fundamentals (SI) - Chapter 1
*/
bool Converged;
bool RHBounded;
double WBTempHi;
double WBTempLo;
double WBTemperature;
double RHCalc_Lo;
double Params[2];
Converged = false;
WBTempHi = DBTemperature;
WBTempLo = DBTemperature - 4.0f;
HINSTANCE MathRoutinesInstance;
if(LoadLibraryFlag == 0)
{
MathRoutinesInstance = LoadLibrary("./MathRoutines.dll");
BisectionRootFinder = (fp_BisectionRootFinderTYPE) GetProcAddress(MathRoutinesInstance,"BisectionRootFinder");
}
// Do some calculations here
if(Converged == true)
WBTemperature = WBTemperature;
else
{
Params[0] = DBTemperature;
Params[1] = Pressure;
WBTemperature = BisectionRootFinder(WBTempLo,WBTempHi,RelHumidity,0.0005,Params,50,RelHumidityfn_WB_Params);
}
if(LoadLibrary == 0)
{
FreeLibrary(MathRoutinesInstance);
}
return WBTemperature;
}
お気づきのとおり、上記の dll は別の dll "MathRoutines.dll" を参照して計算を行います。Function8 には、Mathroutines dll をロードするための if ブロックがありました。これは、function8 が直接呼び出される C# インターフェイス プログラムで dll を使用するためです。関数 8 は MathRoutines.dll の関数を使用するため、直接呼び出されたときにそれを読み込む必要があります。
この設定では、プログラムは元の投稿で述べた問題を抱えていました。凍結はファイルとは何の関係もないことに気付きました。簡単な作業例を作成する際の試みとして、Function8 の次の行にコメントを付けました。
/*
HINSTANCE MathRoutinesInstance;
if(LoadLibraryFlag == 0)
{
MathRoutinesInstance = LoadLibrary("./MathRoutines.dll");
BisectionRootFinder = (fp_BisectionRootFinderTYPE) GetProcAddress(MathRoutinesInstance,"BisectionRootFinder");
}
*/
と
/*
if(LoadLibrary == 0)
{
FreeLibrary(MathRoutinesInstance);
}
*/
さらに、Function1 の最後にある FreeLibrary 呼び出しにもコメントを付ける必要がありました。上記の変更により、アプリケーションは正常に動作します。問題は、C++ で MatRoutines ライブラリをロードする方法に関係していると思われるため、ここでは FORTRAN コードを含めませんでした。
上記の行のコメントがどのように機能したかを知りたいです。DLL をロード/アンロードする正しい方法は何ですか。