I wrote some backend code in C and I wrote a frontend for it in C#. What I want it to do is run the backend code in the background so I can do other things like update a progress bar, but when I click the "Start" button, the program hangs until it's finished running the backend code.
C# code:
[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 code:
extern "C" {
__declspec(dllexport) int executeBackend()
{
int statusCode = 0;
//Do stuff in the background
return statusCode;
}
}
If I comment out the call to run executeBackend and replace it with await Task.Delay(5000);
, the UI doesn't deadlock. How would I fix this?
CodePudding user response:
You can wrap the call to executeBackend
in a Task
to prevent the UI from locking up.
var status = await Task.Run(() => executeBacked());
I also think you're confused about what the async
keyword actually does. I think it might be prudent for you to read up on how Asynchronous Programming works in dotnet.
CodePudding user response:
You need to rethink how your C code handles asynchronicity.
You should be able to pass the C side a callback function, so that you can hand off the whole operation and return a Task
.
Something like this (note the StartProgram
function is using TaskCompletionSource
and is not marked 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);
executeBackend(callback);
return tcs.Task;
}
I'm not familiar enough with C to show you that side, but essentially you need to be able to take a parameter of type void (*) (int)
function pointer, hand off the operation to another thread, and call back the C# side using the function pointer.