Home > Back-end >  Running C code asynchronously in a C# program
Running C code asynchronously in a C# program

Time:08-14

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.

  • Related