diff --git a/Include/nmNum/nmCalculation/nmCalculationUtils.h b/Include/nmNum/nmCalculation/nmCalculationUtils.h index 3688f57..a3a86dd 100644 --- a/Include/nmNum/nmCalculation/nmCalculationUtils.h +++ b/Include/nmNum/nmCalculation/nmCalculationUtils.h @@ -8,6 +8,8 @@ #include "nmCalculationDefine.h" #include +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。 diff --git a/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp b/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp index f240169..912782c 100644 --- a/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp +++ b/Src/nmNum/nmCalculation/nmCalculationDllPebiSolverTask.cpp @@ -21,6 +21,7 @@ #include "nmDataPvtParaForPebi.h" #include +#include #include #include #include @@ -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; } diff --git a/Src/nmNum/nmCalculation/nmCalculationPebiGrid.cpp b/Src/nmNum/nmCalculation/nmCalculationPebiGrid.cpp index 643ef9f..527a3f5 100644 --- a/Src/nmNum/nmCalculation/nmCalculationPebiGrid.cpp +++ b/Src/nmNum/nmCalculation/nmCalculationPebiGrid.cpp @@ -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; } diff --git a/Src/nmNum/nmCalculation/nmCalculationUtils.cpp b/Src/nmNum/nmCalculation/nmCalculationUtils.cpp index e45a18a..69de14a 100644 --- a/Src/nmNum/nmCalculation/nmCalculationUtils.cpp +++ b/Src/nmNum/nmCalculation/nmCalculationUtils.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include @@ -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; } -