fix(numerical): 串行化HX_NWTM.dll调用避免并发冲突

- 增加进程级DLL互斥锁
- 串行保护PEBI建网、模型求解和Kriging调用
- DLL调用完成后及时释放锁,避免阻塞VTK和结果后处理
feature/refactor-numerical-model-panel-20260824
lh 2 weeks ago
parent 25603b4471
commit 3a8b3baef9

@ -8,6 +8,8 @@
#include "nmCalculationDefine.h"
#include <iostream>
class QMutex;
class NMCALCULATION_EXPORT nmCalculationUtils {
public:
nmCalculationUtils();
@ -19,6 +21,9 @@ class NMCALCULATION_EXPORT nmCalculationUtils {
static bool writeFile(const QStringList& content, const QString &filePath);
static QStringList readFile(const QString & filePath);
/** @brief 获取串行保护 HX_NWTM.dll 全部入口的进程级互斥锁。 */
static QMutex* getHxNwtmDllMutex();
/**
* @brief 使西PEBI使西
* @param dPermeabilityMilliDarcy mD

@ -21,6 +21,7 @@
#include "nmDataPvtParaForPebi.h"
#include <QDebug>
#include <QMutexLocker>
#include <QSet>
#include <iostream>
#include <fstream>
@ -630,7 +631,9 @@ bool nmCalculationDllPebiSolverTask::execPebiMode()
return false;
}
// 第四步:解析并配置模型 DLL。此后直到 DLL 返回都只使用局部输出和输入。
// 第四步:建网、模型求解和 Kriging 共用 DLL 全局状态,整个 DLL 调用必须串行。
QMutexLocker oDllLocker(
nmCalculationUtils::getHxNwtmDllMutex());
HMODULE hModelModule = LoadLibrary(L"HX_NWTM.dll");
if(hModelModule == nullptr) {
qWarning() << "Failed to load HX_NWTM.dll. Error code:"
@ -697,12 +700,15 @@ bool nmCalculationDllPebiSolverTask::execPebiMode()
return false;
}
// 后处理只读取本次局部输出,无需继续占用进程级 DLL 锁。
FreeLibrary(hModelModule);
oDllLocker.unlock();
// 第五步:把井曲线和场压力构造成任务局部结果。该函数同样只读取输入快照。
const bool bSucceeded = buildPebiModeResult(
oModelOutput,
oModelInput.T,
oGridResult.m_oGridOutput1);
FreeLibrary(hModelModule);
return bSucceeded;
}

@ -37,7 +37,7 @@ namespace {
const int CONST_PVT_POINT_COUNT = 200;
// PEBI 网格生成器和其 DLL 都使用进程级共享状态,所有公开读写入口必须串行化
// 该锁只保护 PEBI 网格单例缓存HX_NWTM.dll 的所有入口由独立进程级锁保护
// 保留递归锁以兼容可能在持锁网格入口中调用缓存查询的旧代码路径。
QMutex s_oPebiGridMutex(QMutex::Recursive);
@ -1233,6 +1233,9 @@ bool nmCalculationPebiGrid::calculateSnapshot(
return false;
}
// 建网、模型求解和 Kriging 共用 DLL 全局状态,加载至读取结果期间必须串行。
QMutexLocker oDllLocker(
nmCalculationUtils::getHxNwtmDllMutex());
HMODULE hGridModule = LoadLibrary(L"HX_NWTM.dll");
if(hGridModule == nullptr) {
qWarning() << "Failed to load HX_NWTM.dll. Error code:"
@ -1293,6 +1296,11 @@ bool nmCalculationPebiGrid::calculateSnapshot(
oSnapshot.m_sLicensePath.toStdString());
oResult.m_nPebiCount = pfnGetPebiCount();
// 后续 VTK 构造只读取本次局部输出,无需继续占用进程级 DLL 锁。
FreeLibrary(hGridModule);
hGridModule = nullptr;
oDllLocker.unlock();
// 自动拟合只需要 DLL 数组,可跳过 VTK 构造;网格任务必须生成完整 VTK。
if(bCreateUnstructuredGrid) {
oResult.m_pUnstructuredGrid =
@ -1300,7 +1308,6 @@ bool nmCalculationPebiGrid::calculateSnapshot(
oResult.m_oGridOutput1);
if(oResult.m_pUnstructuredGrid == nullptr ||
oResult.m_pUnstructuredGrid->GetNumberOfCells() <= 0) {
FreeLibrary(hGridModule);
return false;
}
}
@ -1310,17 +1317,20 @@ bool nmCalculationPebiGrid::calculateSnapshot(
zxLogInstance::getInstance()->writeLogF(
QString("C++ Exception: %1").arg(e.what()));
logInputParameters(oSnapshot.m_oGridInput);
FreeLibrary(hGridModule);
if(hGridModule != nullptr) {
FreeLibrary(hGridModule);
}
return false;
} catch(...) {
zxLogInstance::getInstance()->writeLogF(
"SEH Exception Occurred");
logInputParameters(oSnapshot.m_oGridInput);
FreeLibrary(hGridModule);
if(hGridModule != nullptr) {
FreeLibrary(hGridModule);
}
return false;
}
FreeLibrary(hGridModule);
return true;
}

@ -5,6 +5,8 @@
#include <QDir>
#include <QDebug>
#include <QCoreApplication>
#include <QMutex>
#include <QMutexLocker>
#include <fstream>
#include <float.h>
@ -12,6 +14,9 @@
namespace
{
// HX_NWTM.dll 的配置和结果查询接口使用进程级共享状态,所有入口共用此锁。
QMutex s_oHxNwtmDllMutex;
QString krigingText(const char* sourceText)
{
return QCoreApplication::translate("nmCalculationUtils", sourceText);
@ -37,6 +42,11 @@ void setKrigingError(QString* errorMessage, const QString& message)
nmCalculationUtils::nmCalculationUtils() {
}
QMutex* nmCalculationUtils::getHxNwtmDllMutex()
{
return &s_oHxNwtmDllMutex;
}
double nmCalculationUtils::milliDarcyToDarcy(double dPermeabilityMilliDarcy)
{
// PEBI输入结构使用D数据层统一使用mD因此仅在求解器边界换算。
@ -267,6 +277,8 @@ bool nmCalculationUtils::calculateKriging(
return false;
}
// Kriging 与建网、模型求解来自同一个 DLL不能在不同线程中并发进入。
QMutexLocker oDllLocker(getHxNwtmDllMutex());
HMODULE dll = LoadLibrary(L"HX_NWTM.dll");
if(dll == NULL) {
setKrigingError(errorMessage, krigingText("Failed to load HX_NWTM.dll."));
@ -354,4 +366,3 @@ bool nmCalculationUtils::calculateKriging(
}
return calculationSucceeded;
}

Loading…
Cancel
Save