0

My original problem is about UI blocking , what I have is two external process that should execute consecutively with some other codes , every process will be executed n times , the two execute of these processes cause UI freeze , To avoid this problem I've implemented backgroundworker Object in my code , the first process ProcessA will be in a backgroundworker and the second ProcessB will be in the backgroundworker .

Let's start with the ProcessA , when I run my application and start execute the whole task , ProcessA will be running so fast and output results ( I didn't know why it runs quickly) , for the results , they seems correct .

ProcessA executed n steps , every step , it will create a new BackgroundWorker to do the job and execute the task in the background.

The second process must executed after the first process finished , my problem for now is that the event of CompletedTask of the first process won't executed , and the second process start before the first completed .

public void ButtonClick(object sender, RoutedEventArgs e)
{

    for (int i = 0; i < steps + 1; i++)
    {
        backgroundworker = new BackgroundWorker();
        backgroundworker.DoWork += new DoWorkEventHandler(BackgroundWorker_DoWork);
        backgroundworker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;

        backgroundworker.RunWorkerAsync(Tuple.Create(mypath, i));
    }

    While(!FirstProcessFinished)
        Thread.Sleep(1000);

    RunSecondProcess(mypath);
}


protected void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    // Some code to run first Process
}


protected void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    Counter++;
    IncrementProgressBar();
    Thread.Sleep();
    Console.WriteLine("Finished");
    if (counter == Steps + 1)
    {
        FirstProcessFinished = true;
    }
}

How can I execute ProcessB correctly after calling n times the backgroundWorker_Completed?

Update :

I've test the solution of the Orace answer , but now I can't execute the second task and the first task won't complete the process:

  private async void Work(string path)
    {
        try
        {
            // start all A tasks
            var aTasks = new List<Task>();
            for (int i = 0; i < steps; i++)
            {
               aTasks.Add(new Task(() => RunA(path, i)));
            }


            // wait for them to end
            await Task.WhenAll(aTasks);

            IncrementProgressBar();

            // start B task (it will not be allowed to update the UI)
            await Task.Run(() => RunB(path));

            IncrementProgressBar();
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw;
        }
    }

  private async Task RunA(string path, int index)
        {
            // start the actual work (new task to not freeze the UI)
            await Task.Run(() => WorkA(path, index));

            // here we are back on the UI thread so we can update the status
            IncrementProgressBar();

            Console.WriteLine($"Task A{index:00} Finished");
        }

What's the wrong here???

  • Does this answer your question? [Need to understand the usage of SemaphoreSlim](https://stackoverflow.com/questions/20056727/need-to-understand-the-usage-of-semaphoreslim) – Eldar Jul 06 '22 at 08:59
  • I'm using `Backgroundworker` not Task and `async` methods . – JuniorDev13 Jul 06 '22 at 09:01
  • `async / await` and `Task` will make your life easier on this one. Does `Backgroundworker` are mandatory? – Orace Jul 06 '22 at 09:02
  • 3
    BackgroundWorker is obsolete. See e.g. [Async/await vs BackgroundWorker](https://stackoverflow.com/questions/12414601/async-await-vs-backgroundworker). – Clemens Jul 06 '22 at 09:07
  • I would suggest to remove the "Update" part of the question, and post it as new question instead. Otherwise your question might be closed for being "Too broad, needs more focus". – Theodor Zoulias Jul 06 '22 at 10:50
  • Please tell me what's the wrong in the update? why it needs more focus?? – JuniorDev13 Jul 06 '22 at 10:52
  • In general is not perceived well here to edit a question, and add a follow-up question that was motivated from an answer to the question. If you decide to follow the advice offered in an answer, and then find some new difficulties along the way, the expected course of action is to post a new question which is specific to the difficulties of implementing the specific advice. For more details, [this](https://meta.stackoverflow.com/questions/417476/question-close-reasons-definitions-and-guidance/417486#417486) might be helpful. – Theodor Zoulias Jul 06 '22 at 11:09
  • I think that my question is cleared as well, I've mentioned the whole scenario and I got answers , unfortunately, all answers seems to not be working in my case , I don't know , also they contains some error code and I'm trying to fix these error and exceptions , I think is it also not good to give an answer with syntax errors . – JuniorDev13 Jul 06 '22 at 11:12
  • The correct place to provide feedback to the author of an answer, is in the comments under the answer. Providing feedback to a specific answer by editing the question creates confusion, and also disincentivizes other people from answering the question. Your question now looks more like a chat between you and Orace. Why would anyone want to intervene in your friendly discussion? – Theodor Zoulias Jul 06 '22 at 12:37
  • When I wrote comments to the author of an answer , I didn't get any answer from him – JuniorDev13 Jul 06 '22 at 13:06

1 Answers1

1

Task, async and await are the way to go. Here is an example of what you can write:

using System;
using System.Linq;
using System.Threading.Tasks;

//------------------------

// async void should be used with caution.
// see: https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming#avoid-async-void
// see: https://johnthiriet.com/mvvm-going-async-with-async-command/
public async void ButtonClick(object sender, RoutedEventArgs e)
{
    try
    {
        // start all A tasks
        var aTasks = Enumerable.Range(0, steps + 1).Select(i => RunA(myPath, i));

        // wait for them to end
        await Task.WhenAll(aTasks);

        // start a new task for B
        // you can't update the UI from the code inside RunB
        // because it will probably run on a different thread
        await Task.Run(() => RunB(myPath));

        // you can update the UI here
        FillProgressBar();
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
        throw;
    }
}

private async Task RunA(string path, int index)
{
    // start a new task for the actual work performed by A
    // you can't update the UI from the code inside WorkA
    // because it will probably run on a different thread
    await Task.Run(() => WorkA(path, index));

    // here the magic happen.
    // We are back on the UI thread so we can update the status
    IncrementProgressBar();

    Console.WriteLine($"Task A{index:00} Finished");
}

private void WorkA(string path, int index)
{
    // the work
}

private void RunB(string path)
{
    // the work
}
Orace
  • 7,822
  • 30
  • 45
  • I'm getting this error : `CS0411 The type arguments cannot be inferred from the usage` What am I doing wrong? – JuniorDev13 Jul 06 '22 at 09:49
  • @JuniorDev13 where ? – Orace Jul 06 '22 at 11:56
  • In : `var aTasks = Enumerable.Range(0, steps + 1).Select(i => RunA(myPath, i));` – JuniorDev13 Jul 06 '22 at 13:08
  • You are missing `using System.Threading.Tasks;` – Orace Jul 06 '22 at 13:26
  • Why you say It will not update the UI ??? my problem is UI blocking and I would like to execute the two tasks without any blocking? – JuniorDev13 Jul 06 '22 at 14:03
  • It's an example. You can update the UI in `RunA` but you can't **in** `RunB` (it runs in a new task that can be on the wrong thread). If you want to update the UI **in** `RunB` apply the same pattern as `RunA`. (ie: call it with `await RunB(...)` and declare it like that: `async Task RunB(...)`. – Orace Jul 06 '22 at 14:07
  • The problem now , is that Task 2 won't await for the task 1 . – JuniorDev13 Jul 06 '22 at 14:10
  • What are Task 2 and Task 1 ? Are you talking of `RunA` with `i = 0` and `i = 1` ? – Orace Jul 06 '22 at 14:14
  • Task1 is RunA and Task2 is RunB , the two methods will call a two external process with some other codes ( preprocessing ) – JuniorDev13 Jul 06 '22 at 14:16
  • Your issue then is that `RunA` end after starting the external process without waiting for it to end. And this is another subject that is [already covered](https://stackoverflow.com/a/67230544/361177). – Orace Jul 06 '22 at 14:19
  • I've already test this approach , and I get a UI blocking . – JuniorDev13 Jul 06 '22 at 14:34