Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Invoking causes Task never complete

This is my code:

public void ReadCodes(){
        Task compute = Task.Run(() =>
        {
             //foo code
             foreach (var line in lines)
             {
                 //some other codes
                 SetText("doing something");
             }
        });
        compute.Wait();
        //some other foo
}
private void SetText(string text)
{
        if (this.lblUsedFiles.InvokeRequired)
        {
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { text });
        }
        else
        {
                this.lblUsedFiles.Text = text;
        }
}

When I remove SetText("doing something") call ReadCodes() function works, otherwise it hangs. What's wrong with my code? I want to update UI inside Task.Run().

like image 578
Maysam Avatar asked May 06 '26 07:05

Maysam


1 Answers

Your ReadCodes method (which presumably executes on the UI thread) spawns a new task, and blocks to wait for it – the UI thread can do nothing else until it completes.

However, your task (which runs on the thread pool) calls Invoke to run an operation on the UI thread, also blocking until this completes. Since both operations are blocked waiting for each other, neither can proceed, resulting in a deadlock.

To resolve, the easiest solution is typically to replace your Invoke with BeginInvoke, allowing your task to proceed (and complete) without waiting for the UI update. Once the task does complete, the UI thread is freed, and processes the pending UI update.

Edit: In response to the question being updated to include a loop: I would suggest that you use the asynchronous pattern (introduced in C# 5). This would eliminate UI thread blocking altogether, and allow you to perform UI updates as soon as each line is processed.

public async Task ReadCodes()
{
    foreach (var line in lines)
    {
        string text = await Task.Run(() =>
        {
            //foo code
            // return text;
        });

        this.lblUsedFiles.Text = text;
    }
    //some other foo
}

Edit2: I've updated my code based on Peter Duniho's comment. Since ReadCodes is presumably called on the UI thread, you can update the UI directly within it (without needing Invoke) upon awaiting each task. I'm assuming that the background processing performed in //some other codes can be integrated into the subsequent iteration's //foo code.

like image 153
Douglas Avatar answered May 09 '26 00:05

Douglas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!