внёс изменения, файлы сейчас: #include "pch.h" BO...

Erstellt am: 19. September 2025

Beantwortet mit GPT-5 Thinking von Chat01

Frage

внёс изменения, файлы сейчас: #include "pch.h"

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
DisableThreadLibraryCalls(hModule);
}
return TRUE;
} - dllmain, static std::unique_ptrboost::mpi::environment g_env;
static std::unique_ptrboost::mpi::communicator g_world;
static std::unique_ptr<PeanoCurve_2D> Curve, Curve_Inverted;

extern "C" __declspec(dllexport) int __cdecl AgpInit(int peanoLevel, float a, float b, float c, float d) {
if (!g_env) g_env = std::make_uniqueboost::mpi::environment(); // MPI_Init()
if (!g_world) g_world = std::make_uniqueboost::mpi::communicator(); // MPI_COMM_WORLD
int rank = g_world->rank();
if (rank == 0) Curve = std::make_unique<PeanoCurve_2D>(List::Top, peanoLevel, a, b, c, d);
else if (rank == 1) Curve_Inverted = std::make_unique<PeanoCurve_2D>(List::Down, peanoLevel, a, b, c, d);
return rank;
}

extern "C" __declspec(dllexport) void __cdecl AgpFinalize() {
Curve_Inverted.reset();
Curve.reset();
g_world.reset();
g_env.reset(); // MPI_Finalize()
}

__declspec(align(16u)) struct CrossMsg final {
float s_x1, s_x2;
float e_x1, e_x2;
float Rtop;
template <typename Archive>
__declspec(noalias) __forceinline void serialize(Archive& __restrict ar, const uint64_t) noexcept { ar& s_x1& s_x2& e_x1& e_x2& Rtop; }
};

extern "C" __declspec(dllexport) __declspec(noalias) void Base_LNA_1_2_Mer_AGP(
const float N, const float global_iterations, const float a, const float b, const float c, const float d, const float r,
const bool mode, const float epsilon, const double seed,
float** out_data, uint64_t* out_len) noexcept
{
if (N == 1.0f) {
const float initial_length = b - a;
float dmax = initial_length;
const float start_val = ShekelFunc(a, seed);
float best_f = ShekelFunc(b, seed);
float schetchick = 0.0f;

text
std::pair<float, float> x_Rmax{ a, b }; std::pair<float, float> y_Rmax{ start_val, best_f }; std::vector<float> Extr; Extr.reserve(global_iterations * 4u); std::vector<std::unique_ptr<Interval>> R; R.reserve(global_iterations * 2u); // Создаем начальный интервал R.emplace_back(std::make_unique<Interval>(std::make_pair(a, start_val), std::make_pair(b, best_f), N)); float Mmax = R.front()->M; float m = r * Mmax; const float threshold_03 = 0.3f * initial_length; const float inv_threshold_03 = 1.0f / threshold_03; while (true) { const float new_point = Shag(m, x_Rmax.first, x_Rmax.second, y_Rmax.first, y_Rmax.second, N, r); const float new_value = ShekelFunc(new_point, seed); const std::pair<float, float> promejutochnaya_tochka{ new_point, new_value }; if (new_value < best_f) { best_f = new_value; Extr.emplace_back(best_f); Extr.emplace_back(new_point); } // Извлекаем максимальный интервал std::pop_heap(R.begin(), R.end(), ComparePtr); const std::unique_ptr<Interval> promejutochny_otrezok = std::move(R.back()); R.pop_back(); const size_t r_size = R.size(); const float len2 = promejutochny_otrezok->end.first - new_point; const float len1 = new_point - promejutochny_otrezok->start.first; const float dmin = len1 < len2 ? len1 : len2; // Условие завершения if (++schetchick == global_iterations || dmin < epsilon) { Extr.emplace_back(schetchick); Extr.emplace_back(dmin); // Копируем данные в выходной буфер *out_len = Extr.size(); *out_data = reinterpret_cast<float*>(CoTaskMemAlloc(sizeof(float) * (*out_len))); memcpy(*out_data, Extr.data(), sizeof(float) * (*out_len)); return; } // Создаем новые интервалы std::unique_ptr<Interval> curr = std::make_unique<Interval>(promejutochny_otrezok->start, promejutochnaya_tochka, N); std::unique_ptr<Interval> curr1 = std::make_unique<Interval>(promejutochnaya_tochka, promejutochny_otrezok->end, N); const float currM = curr->M > curr1->M ? curr->M : curr1->M; if (len2 + len1 == dmax) { dmax = len2 > len1 ? len2 : len1;

#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
const float len = R[i]->end.first - R[i]->start.first;
if (len > dmax) {
dmax = len;
}
}
}

text
if (mode) { if (threshold_03 > dmax && fmodf(schetchick, 3.0f) == 0.0f || 10.0f * dmax < initial_length) { if (currM > Mmax) { Mmax = currM; m = r * Mmax; } const float progress = fmaf(-inv_threshold_03, dmax, 1.0f); const float alpha = fmaf(progress, progress, 1.0f); const float betta = 2.0f - alpha; const float MULTIPLIER = (1.0f / dmax) * Mmax; const float global_coeff = fmaf(MULTIPLIER, r, -MULTIPLIER); const float GLOBAL_FACTOR = betta * global_coeff; curr->ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len1, curr->M * alpha)); curr1->ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len2, curr1->M * alpha));

#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
const float len_item = R[i]->end.first - R[i]->start.first;
R[i]->ChangeCharacteristic(fmaf(GLOBAL_FACTOR, len_item, R[i]->M * alpha));
}
std::make_heap(R.begin(), R.end(), ComparePtr);
}
else {
if (currM > Mmax) {
Mmax = currM;
m = r * Mmax;
curr->ChangeCharacteristic(m);
curr1->ChangeCharacteristic(m);
#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
R[i]->ChangeCharacteristic(m);
}
std::make_heap(R.begin(), R.end(), ComparePtr);
}
else {
curr->ChangeCharacteristic(m);
curr1->ChangeCharacteristic(m);
}
}
}
else {
if (currM > Mmax) {
Mmax = currM;
m = r * Mmax;
curr->ChangeCharacteristic(m);
curr1->ChangeCharacteristic(m);
#pragma loop(ivdep)
for (size_t i = 0u; i < r_size; ++i) {
R[i]->ChangeCharacteristic(m);
}
std::make_heap(R.begin(), R.end(), ComparePtr);
}
else {
curr->ChangeCharacteristic(m);
curr1->ChangeCharacteristic(m);
}
}

text
// Добавляем новые интервалы R.emplace_back(std::move(curr)); R.emplace_back(std::move(curr1)); std::push_heap(R.begin(), R.end(), ComparePtr); // Обновляем x_Rmax и y_Rmax const std::unique_ptr<Interval>& top = R.front(); x_Rmax = { top->start.first, top->end.first }; y_Rmax = { top->start.second, top->end.second }; } } else { // Простая заглушка для двумерной ветки const int rank = g_world->rank(); const int partner = (rank == 0) ? 1 : 0; // Простые вычисления float simple_value = rank * 10.0f + 5.0f; float received_value = 0.0f; // Простая MPI-коммуникация if (rank == 0) { g_world->send(partner, 0, simple_value); g_world->recv(partner, 0, received_value); } else { g_world->recv(partner, 0, received_value); received_value += 1.0f; // Небольшое вычисление g_world->send(partner, 0, received_value); } // Создаем небольшой вектор с результатами std::vector<float> simple_results; simple_results.push_back(simple_value); simple_results.push_back(received_value); simple_results.push_back(static_cast<float>(rank)); // Копируем данные в выходной буфер *out_len = simple_results.size(); *out_data = reinterpret_cast<float*>(CoTaskMemAlloc(sizeof(float) * (*out_len))); memcpy(*out_data, simple_results.data(), sizeof(float) * (*out_len)); // Синхронизация перед завершением g_world->barrier(); return; }

}

extern "C" __declspec(dllexport) void __cdecl Base_LNA_1_2_Mer_AGP_Free(float* p) {
CoTaskMemFree(p);
}

// В DLL
extern "C" __declspec(dllexport) void __cdecl AgpStartWorkers() {
int go = 1;
MPI_Bcast(&go, 1, MPI_INT, /root=/0, MPI_COMM_WORLD);
}

extern "C" __declspec(dllexport) void __cdecl AgpWaitStartAndRun() {
int go = 0;
MPI_Bcast(&go, 1, MPI_INT, /root=/0, MPI_COMM_WORLD); // блокируется, пока мастер не пошлёт
if (go == 1) {
float* dummy = nullptr; uint64_t dummy_len = 0;
Base_LNA_1_2_Mer_AGP(2.0f, 10000.0f, -2.2f, 1.8f, -2.2f, 1.8f,
2.5f, false, 0.0001f, GetTickCount(),
&dummy, &dummy_len);
if (dummy) Base_LNA_1_2_Mer_AGP_Free(dummy);
}
} - основной .cpp файл библиотеки с заглушкой, #include "MyForm.h"
#include <float.h>

using namespace System;
using namespace System::Windows::Forms;

typedef int (*PInit)(int, float, float, float, float);
typedef void (*PFin)();

[STAThread]
int main() {
HMODULE h = LoadLibraryW(L"TEST_FUNC.dll");
auto AgpInit = (PInit)GetProcAddress(h, "AgpInit");
auto AgpFinalize = (PFin)GetProcAddress(h, "AgpFinalize");
if (!h || !AgpInit || !AgpFinalize) { MessageBox::Show(L"Не удалось инициализировать DLL/MPI"); return 1; }

text
const int rank = AgpInit(12, -2.2f, 1.8f, -2.2f, 1.8f); if (rank == 0) { Application::EnableVisualStyles(); Application::SetCompatibleTextRenderingDefault(false); TESTAGP::MyForm form(h); Application::Run(% form); //Application::Run(gcnew TESTAGP::MyForm(h)); } else { // Воркер-процесс: ждёт команды "старт" и выполняет расчёт без UI typedef void(__cdecl* PStartWorkers)(); auto AgpWaitStartAndRun = (PStartWorkers)GetProcAddress(h, "AgpWaitStartAndRun"); if (AgpWaitStartAndRun) AgpWaitStartAndRun(); // см. пункт D } AgpFinalize(); FreeLibrary(h); return 0;

} - MyForm.cpp, ref class MyForm : public System::Windows::Forms::Form {
public:
MyForm(HMODULE hLib) { // Передаем дескриптор из main
this->hLib = hLib;
InitializeComponent();
// Загружаем функции из DLL
f = (agp_c)GetProcAddress(hLib, "Base_LNA_1_2_Mer_AGP");
ffree = (agp_free)GetProcAddress(hLib, "Base_LNA_1_2_Mer_AGP_Free");
pStart = (start_workers)GetProcAddress(hLib, "AgpStartWorkers");
}

text
protected: ~MyForm() { delete components; } private: HINSTANCE hLib = nullptr; typedef void(*agp_c)(float, float, float, float, float, float, float, bool, float, double, float**, uint64_t*); typedef void(*agp_free)(float*); typedef void(__cdecl* start_workers)(); agp_c f = nullptr; agp_free ffree = nullptr; start_workers pStart = nullptr; System::Windows::Forms::Button^ button1; System::Windows::Forms::TextBox^ textBox2; System::Windows::Forms::DataVisualization::Charting::Chart^ chart2; System::Windows::Forms::Label^ label2; System::Windows::Forms::Label^ label3; System::Windows::Forms::TextBox^ textBox1; System::Windows::Forms::TextBox^ textBox3; System::Windows::Forms::TextBox^ textBox4; System::Windows::Forms::TextBox^ textBox5; System::Windows::Forms::TextBox^ textBox6; System::Windows::Forms::Label^ label6; System::Windows::Forms::Label^ label7; System::Windows::Forms::Label^ label8; System::Windows::Forms::Label^ label9; System::Windows::Forms::Label^ label10; System::Windows::Forms::Label^ label1; System::Windows::Forms::TextBox^ textBox7; System::Windows::Forms::TextBox^ textBox8; System::ComponentModel::Container^ components; System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { chart2->Series[0]->Points->Clear(); chart2->Series[1]->Points->Clear(); chart2->Series[2]->Points->Clear(); chart2->Series[3]->Points->Clear(); static LARGE_INTEGER start, end; QueryPerformanceCounter(&start); const double seed = GetTickCount(); float* buf = nullptr; uint64_t len = 0u; // Вызов для 2D ветки (N = 2.0f) //auto pStart = (void(__cdecl*)())GetProcAddress(hLib, "AgpStartWorkers"); if (pStart) pStart(); // разбудили rank != 0 f(2.0f, 10000.0f, -2.2f, 1.8f, -2.2f, 1.8f, 2.5f, false, 0.0001f, seed, &buf, &len); if (buf != nullptr) { std::vector<float> Extr_2D(buf, buf + len); ffree(buf); - MyForm.h, при запуске через mpiexec получаю: C:\Users\maxim>mpiexec -n 2 D:\TEST_AGP\x64\Release\TEST_AGP.exe

Необработанное исключение: System.Runtime.InteropServices.SEHException: Внешний компонент создал исключение.
в main() в D:\TEST_AGP\MyForm.cpp:строка 28
в mainCRTStartup()

job aborted:
[ranks] message

[0] terminated

[1] process exited without calling finalize

---- error analysis -----

[1] on DESKTOP-C1VT6JF
D:\TEST_AGP\x64\Release\TEST_AGP.exe ended prematurely and may have crashed. exit code 0xc000001d

---- error analysis ----- - внимательно проверь все сигнатуры, типы, код ошибки, правильность инициализации mpi, о чём говорит ошибка и в чём скорее всего дело

Gedanke

Analyzing MSVC and MPI behavior

In MSVC, the default calling convention is __cdecl, which matches the typedef void (*f)(). Boost.MPI usage alongside raw MPI calls like MPI_Bcast seems fine, as long as the MPI environment—via boost::mpi::environment—is active. Mixing MS-MPI with Boost.MPI requires careful attention to matching builds. The error code 0xc000001d indicates an "Illegal Instruction" exception, often related to incorrect architecture or misconfiguration.

Investigating 0xc000001d exception

The 0xc000001d exception could be caused by unsupported CPU instructions (AVX, SSE4.2) or faulty function pointers leading to stack corruption and invalid instructions. This might happen with mismatched calling conventions like stdcall vs. cdecl, though access violations typically occur in those cases. Keep in mind, in x86, __cdecl functions might be decorated with an underscore.

Investigating AgpInit crash

They’re compiling the x64 Release version, where name decoration doesn't use a leading underscore. The exports, using extern "C" and __cdecl, should match the function lookup. They load the DLL with LoadLibraryW, which seems fine as they get the function pointer. However, the crash at line 28 could be related to the call to AgpInit, or possibly due to MPI environment initialization.

Investigating rank crash issue

The exit code 0xc000001d suggests one process crashed while the other terminated, possibly due to unhandled exceptions. There's a potential issue with g_world being null, especially in the else branch where it accesses g_world->rank(). Also, the unshown ComparePtr comparator function might be a factor, but it’s unclear. The code structure involving MPI_Bcast and worker synchronization could be leading to the issue when rank 0 communicates.

Investigating crash at startup

The mix of raw MPI and Boost.MPI within a Windows Forms app and the use of /clr in C++/CLI creates potential issues with initialization and function pointer mismatches. The 0xc000001d error could be from calling AVX2-specific instructions on unsupported CPUs, such as fmaf. Additionally, the mixing of MPI libraries may be responsible for the crash when processes do not finalize correctly. The worker process might be misconfigured with MPI_Init; proper synchronization using MPI and Boost could resolve issues.

Investigating crash at line 28

I think the issue might involve a pointer mismatch or function pointer issue in the C++/CLI code. The 0xc000001d error could be due to an illegal instruction, often from using unsupported CPU instructions like FMA. The crash at rank 1’s process exit could relate to improper initialization, architecture mismatches, or missing dependencies like MS-MPI. Also, the use of CoTaskMemAlloc might be contributing to memory management issues. Let’s narrow down potential causes.

Analyzing crash at rank 1

The issue could stem from several areas—incorrect handling of function pointers, mismatched calling conventions, or MPI initialization issues. The crash at line 28 suggests something went wrong earlier, possibly during AgpInit. The potential cause could be mixed runtime libraries, or incorrect setup during MPI initialization, triggering the illegal instruction.

Proposing debugging steps

The issue might come from mismatches in call conventions or runtime libraries, especially with GetProcAddress. It’s essential to ensure consistency in function signatures (e.g., using __cdecl explicitly) and to check pointers for nullptr. Also, ensure that both Boost.MPI and C MPI share the same MS-MPI version, and align the runtime libraries. Testing step-by-step would help pinpoint the exact cause.

Proposing debugging steps

The issue likely arises from mismatched calling conventions or incorrect compilation settings like AVX2/FMA. To start, ensure function signatures are consistent (use __cdecl on exports) and verify pointers are not null. Specific MPI configuration, like checking the runtime version, and proper environment initialization are key steps.

Diagnosing illegal instruction crashes

The 0xc000001d error might come from a mismatch in calling conventions or compiler settings like /Gv (vector call), leading to a crash due to different register usage. Adding __cdecl to both the function and typedef, along with checking null pointers, should resolve this. Also, ensure consistent compiler options and ABI compatibility.

Thought for 3m 37s

Antwort

Коротко: ваш креш с кодом 0xC000001D — это EXCEPTION_ILLEGAL_INSTRUCTION (“недопустимая инструкция”). В практике Windows такое чаще всего случается из-за несовпадения соглашений о вызовах/прототипов при GetProcAddress (регистры/стек портятся → прыжок в мусор/после ретёрна CPU читает «инструкции» из мусора) или потому что бинарник собран с инструкциями (AVX/AVX2/FMA), которых нет у процессора. По вашему коду основной красный флаг — несогласованное соглашение о вызове у Base_LNA_1_2_Mer_AGP: экспорт объявлен без __cdecl, а у вас может быть включён /Gv (__vectorcall по умолчанию). Тогда снаружи вы вызываете её как __cdecl → UB и часто именно 0xC000001D.

Ниже — разбор по пунктам, что проверить и что поправить.


1) Прототипы и соглашения о вызовах

Что у вас сейчас

  • AgpInit / AgpFinalizeок, явно extern "C" + __cdecl, и такие же typedef’ы.
  • AgpStartWorkers / AgpWaitStartAndRunок, тоже __cdecl и совпадающие typedef’ы.
  • Base_LNA_1_2_Mer_AGP — экспорт без явного __cdecl.
    В MyForm.h typedef agp_c тоже без явного __cdecl.

На x64 по умолчанию действительно «как бы» __cdecl, но если в проекте DLL стоит Project → C/C++ → Advanced → Calling Convention = /Gv (то есть __vectorcall по умолчанию) — эта функция внутри DLL станет __vectorcall, а вы извне зовёте её как __cdecl. Это типичный рецептик для «недопустимой инструкции».

Что сделать (обязательно):

  1. В DLL добавить __cdecl ко всем экспортам, в т.ч. к двум «большим» функциям:
cpp
extern "C" __declspec(dllexport) void __cdecl Base_LNA_1_2_Mer_AGP( float N, float global_iterations, float a, float b, float c, float d, float r, bool mode, float epsilon, double seed, float** out_data, uint64_t* out_len) noexcept; extern "C" __declspec(dllexport) void __cdecl Base_LNA_1_2_Mer_AGP_Free(float* p);
  1. В приложении точно так же прописать __cdecl в typedef’ах:
cpp
typedef int (__cdecl *PInit)(int, float, float, float, float); typedef void (__cdecl *PFin)(); typedef void (__cdecl *agp_c)(float, float, float, float, float, float, float, bool, float, double, float**, uint64_t*); typedef void (__cdecl *agp_free)(float*); typedef void (__cdecl *start_workers)();
  1. После GetProcAddress обязательно проверять все указатели (не только pStart, как сейчас), и если nullptr — показать GetLastError() и не вызывать:
cpp
f = reinterpret_cast<agp_c>(GetProcAddress(hLib, "Base_LNA_1_2_Mer_AGP")); ffree = reinterpret_cast<agp_free>(GetProcAddress(hLib, "Base_LNA_1_2_Mer_AGP_Free")); if (!f || !ffree) { MessageBox::Show(L"Не найден экспорт Base_LNA... в DLL"); AgpFinalize(); FreeLibrary(hLib); return 1; }
  1. На всякий случай убедитесь, что в обоих проектах (EXE и DLL) стоит одинаковая опция Project → C/C++ → Advanced → Calling Convention = “Default” (а не /Gv). Если очень нужен __vectorcall, помечайте локально конкретные функции в обоих местах одинаково.

2) Проверка экспорта имён

Иногда имя в экспорте не совпадает с тем, что вы ищете (особенно при разных соглашениях вызова на x86). Быстрый тест:

dumpbin /exports TEST_FUNC.dll

Убедитесь, что видите ровно AgpInit, AgpFinalize, AgpStartWorkers, AgpWaitStartAndRun, Base_LNA_1_2_Mer_AGP, Base_LNA_1_2_Mer_AGP_Free (без декораций). Если название иное — GetProcAddress вернёт NULL, а вызов «мусора» даст тот же 0xC000001D.


3) Что означает 0xC000001D и альтернативные причины

  • 0xC000001D = Illegal instruction.
    На втором месте после несоответствия calling convention — инструкции AVX/AVX2/FMA на процессоре без поддержки. Если у вас в проекте выставлено /arch:AVX2 (или включено автогенерирование FMA с /fp:fast) — попробуйте временно пересобрать DLL и EXE с /arch:SSE2 (или без AVX/FMA) и проверить. Особенно характерно, если падает в Release сразу при входе в функцию.

  • Неверный прототип может повредить регистры/стек и привести к прыжку «в никуда». Это и даёт эффект «недопустимой инструкции». Ваша ситуация этому полностью соответствует из-за отсутствия __cdecl у Base_LNA_1_2_Mer_AGP.


4) MPI: инициализация/финализация и смешение Boost.MPI + C MPI

Ваши зоны риска здесь:

  • Динамическая загрузка в DLL: вы корректно создаёте boost::mpi::environment в AgpInit и уничтожаете в AgpFinalize — хорошо. В DllMain ничего лишнего (только DisableThreadLibraryCalls) — тоже правильно.
  • Смешение Boost.MPI и «сырого» C MPI: допустимо, если это одна и та же реализация (MS-MPI) и MPI_Init/Finalize вызываются ровно один раз на процесс (у вас это делает boost::mpi::environment). Это условие выполняется.
  • MPI_Bcast для старта воркеров: ваш AgpStartWorkers() (root=0 шлёт go=1) и AgpWaitStartAndRun() (ждёт, затем запускает) — корректная схема. Ловушка: не вызывайте AgpStartWorkers() повторно, иначе воркер будет ждать второй широковещательный вызов.
  • Барьер перед финализацией — вы уже делаете g_world->barrier(); в конце ветки N != 1.0f, это правильно, иначе один процесс мог бы уйти в MPI_Finalize, пока другой в Bcast.

Весь этот блок выглядит адекватно; он не объясняет 0xC000001D. Основной источник креша — выше (ABI/инструкции).


5) Ещё мелкие замечания

  • Проверяйте LoadLibrary и все функции (вы уже проверяете часть, но добавьте f/ffree, см. выше).
  • Совместимость CRT по границе DLL: вы грамотно используете CoTaskMemAlloc/CoTaskMemFree — безопасно между разными CRT, так и оставьте.
  • extern "C" у всех экспортов — уже хорошо. Сохраните везде одинаковый набор: extern "C" __declspec(dllexport) __cdecl.
  • Типы совпадают: bool на MSVC — 1 байт и в нативном C++/CLI это тот же bool, здесь ок. uint64_t* совпадает на x64.
  • Диагностика: если нужно, временно соберите DLL без __declspec(noalias), __forceinline, без /GL (LTCG) — чтобы упростить стек и символы на время отладки.

6) Мини-патч (суть правок)

DLL (заголовки экспортов):

cpp
extern "C" __declspec(dllexport) int __cdecl AgpInit(int, float, float, float, float); extern "C" __declspec(dllexport) void __cdecl AgpFinalize(); extern "C" __declspec(dllexport) void __cdecl Base_LNA_1_2_Mer_AGP( float N, float global_iterations, float a, float b, float c, float d, float r, bool mode, float epsilon, double seed, float** out_data, uint64_t* out_len) noexcept; extern "C" __declspec(dllexport) void __cdecl Base_LNA_1_2_Mer_AGP_Free(float* p); extern "C" __declspec(dllexport) void __cdecl AgpStartWorkers(); extern "C" __declspec(dllexport) void __cdecl AgpWaitStartAndRun();

EXE (typedef’ы):

cpp
typedef int (__cdecl *PInit)(int, float, float, float, float); typedef void (__cdecl *PFin)(); typedef void (__cdecl *agp_c)(float, float, float, float, float, float, float, bool, float, double, float**, uint64_t*); typedef void (__cdecl *agp_free)(float*); typedef void (__cdecl *start_workers)();

И проверки на nullptr для f/ffree.


Итог

  • Ошибка 0xC000001D в вашем кейсе почти наверняка вызвана несовпадением соглашения о вызове у Base_LNA_1_2_Mer_AGP (в DLL могла стать __vectorcall, а вызываете как __cdecl). Добавьте явный __cdecl и в экспорт, и в typedef — это критично.
  • Вторым делом исключите фактор /arch:AVX2/FMA (на время — пересоберите без них).
  • Остальная логика MPI и аллокации памяти выглядит корректной.

После этих правок запуск через
mpiexec -n 2 D:\TEST_AGP\x64\Release\TEST_AGP.exe
должен перестать падать уже на входе. Если после исправления ABI появятся уже «обычные» ошибки (например, AV/таймаут/дедлок), их будет проще отладить дальше.

Diesen Q&A teilen