St0ffer
St0ffer

Reputation: 171

Update progressbar from nested Parallel.ForEach

I am rewriting some code to use TPL instead of BackgroundWorkers and implementing multi-threading at the same time. I have everything running fine (runs in parallel and cancellation works as well) but cannot figure out how to update my progressbar appropriately. This is what I have so far (not going to write the full task since it's pretty big):

UPDATE: I have updated the code with the changes I have tried from some of the suggestions.

var progressHandler = new Progress<int>(value => { pgbOverviewProgressbar.Value = value; });
progress = progressHandler as IProgress<int>;

await Task.Run(() => taskGetOverviewData(ct), ct);

public void taskGetOverviewData(CancellationToken ct)
{
    DateTime dtTime2 = DateTime.Now;
    int totalcount = lstDKCZ.Count * lstPTST.Count;
    double iCounter = 0;

    Parallel.ForEach(lstDKCZ, item =>
        {
            Parallel.ForEach(lstPTST, item2 =>
                {
                    //Lots of SQL queries and whatnot

                    double iCount = overview.Count();

                    foreach(var item3 in overview)
                    {
                        //Again lots of things happening

                        if (DateTime.Now > dtTime2.AddMilliseconds(15))
                        {
                            if (iCounter != iCount)
                                progress.Report(Convert.ToInt32((iCounter / iCount) * 100 / totalcount);

                            dtTime2 = DateTime.Now;
                        }
                    }
              }
       }
}

A maximum of 4 parallel iterations are carried out (2 elements in lstDKCZ and 2 elements in lstPTST). This worked fine when doing the work sequentially, well kind of, since the progressbar would just run 4 times (and I just want it to run one time for the whole process). Now it just jumps up and down sporadically, but that is expected and easy enough to understand why (updating the same variable from 4 different threads).

But how do I approach this? I saw locking mentioned while searching for an answer, but I do not quite understand how to implement it in this scenario.

UPDATE 2: Make 4 different progress reports for each scenario. How to merge them?

if (DateTime.Now > dtTime2.AddMilliseconds(15))
{
    if (iCounter != iCount)
    {
        //Make 4 different of these for each scenario
        if (item == "DK" && item2 == "PT")
            progress1.Report(Convert.ToInt32((iCounter / iCount) * 100))                             
        dtTime2 = DateTime.Now;
    }
}

Then what I would want (as far as I understand) is something like:

totalprogress = (progress1 + progress2 + progress3 + progress4) / totalcount;

I cannot seem to get this right though, as I cannot convert the progresses into an integer and pass that value to the totalprogress.

Upvotes: 0

Views: 992

Answers (1)

ShayD
ShayD

Reputation: 930

How about if you divide the progress by the length of lstDKCZ and lstPTST?

int totalCount = lstDKCZ.Count * lstPTST.Count;
Parallel.ForEach(lstDKCZ, item =>
    {
        Parallel.ForEach(lstPTST, item2 =>
            {
                //Lots of SQL queries and whatnot

                double iCount = overview.Count();
                double iCounter = 0;

                foreach(var item3 in overview)
                {
                    //Again lots of things happening

                    if (DateTime.Now > dtTime2.AddMilliseconds(15))
                    {
                        if (iCounter != iCount)
                            progress.Report(Convert.ToInt32((iCounter / iCount) * 100 / totalCount);

                        dtTime2 = DateTime.Now;
                    }
                }
          }
   }

Upvotes: 1

Related Questions