在C#程序中异步运行C++代码

Running C++ code asynchronously in a C# program

本文关键字:运行 C++ 代码 异步 程序      更新时间:2024-09-28

我用C++编写了一些后端代码,并用C#编写了前端代码。我想让它在后台运行后端代码,这样我就可以做其他事情,比如更新进度条,但当我点击";启动";按钮,程序将挂起,直到完成后端代码的运行。

C#代码:

[DllImport("backend.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int executeBackend();
private async void startButton_Click(object sender, EventArgs e)
{
startButton.Enabled = false;
await StartProgram();
}
private async Task StartProgram()
{
int status = 0;
status = executeBackend(); //This is causing the UI to deadlock
startButton.Enabled = true;
}

backend.dll C++代码:

extern "C" {
__declspec(dllexport) int executeBackend()
{
int statusCode = 0;
//Do stuff in the background
return statusCode;
}
}

如果我注释掉运行executeBackend的调用,并将其替换为await Task.Delay(5000);,则UI不会死锁。我该怎么解决这个问题?

您可以将对executeBackend的调用封装在Task中,以防止UI锁定。

var status = await Task.Run(() => executeBacked());

我还认为您对async关键字的实际作用感到困惑。我认为您应该仔细阅读异步编程在dotnet中的工作原理。

您需要重新思考C++代码如何处理异步性

您应该能够向C++端传递一个回调函数,这样您就可以传递整个操作并返回一个Task

类似于此(请注意,StartProgram函数使用TaskCompletionSource,并且标记为async。(

[DllImport("backend.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void executeBackend(BackendCallback func);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void BackendCallback(int result);
private Task<int> StartProgram()
{
var tcs = new TaskCompletionSource<int>();
BackendCallback callback = result =>
{
tcs.SetResult(result);
GC.KeepAlive(callback);  // prevent GC from disposing unmanaged callback
};
executeBackend(callback);
return tcs.Task;
}

我对C++不够熟悉,无法向您展示这一面。

但本质上,您需要能够获取void (*) (int)函数指针类型的参数,将操作交给另一个线程,然后在完成时使用函数指针回调C#端。