Why is using WaitAll within a task causing issues?

  • (2 Pages)
  • +
  • 1
  • 2

17 Replies - 10969 Views - Last Post: 01 August 2012 - 02:48 PM Rate Topic: -----

#1 adn258   User is offline

  • D.I.C Addict

Reputation: 12
  • View blog
  • Posts: 816
  • Joined: 31-August 11

Why is using WaitAll within a task causing issues?

Posted 31 July 2012 - 09:14 AM

So In the code below it works fine adding files to a listbox without crashing though I don't know if I should start a task within a using( but in any case here it is

 using (OpenFileDialog sf = new OpenFileDialog())
                    {
                        sf.Multiselect = true;
                        sf.Title = "Select Files For Conversion Of The Same File Type Like Images";
                        if (sf.ShowDialog() == DialogResult.OK)
                        {
                            this.LblStatus.Text = "Status:Adding Files Please Wait...";
                            Task.Factory.StartNew(() =>
                            {
                                foreach (string ifile in sf.FileNames)
                                {
                                    DoGUIAction(() => this.LstBxFilesToConvert.Items.Add(ifile));
                                    Thread.Sleep(5);
                                }
                            });
                            
                        }
                    }
                  





Now I have major issues if I use the below which uses Task.WaitAll( the issues is it only ADDS ONE FILE repeating with the same name to the listbox that I have; why does it do that?

 using (OpenFileDialog sf = new OpenFileDialog())
                    {
                        sf.Multiselect = true;
                        sf.Title = "Select Files For Conversion Of The Same File Type Like Images";
                        if (sf.ShowDialog() == DialogResult.OK)
                        {
                            this.LblStatus.Text = "Status:Adding Files Please Wait...";
                            Task.WaitAll(Task.Factory.StartNew(() =>
                            {
                                foreach (string ifile in sf.FileNames)
                                {
                                    DoGUIAction(() => this.LstBxFilesToConvert.Items.Add(ifile));
                                    Thread.Sleep(5);
                                }
                            }));
                            
                        }
                    }
                  


This post has been edited by adn258: 31 July 2012 - 09:15 AM


Is This A Good Question/Topic? 0
  • +

Replies To: Why is using WaitAll within a task causing issues?

#2 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 7449
  • View blog
  • Posts: 25,091
  • Joined: 05-May 12

Re: Why is using WaitAll within a task causing issues?

Posted 31 July 2012 - 09:31 AM

Are you sure it isn't your DoGUIAction() that is doing the duplication?

I'm only seeing one call with this test code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;


namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Task.WaitAll(Task.Factory.StartNew(() =>
            {
                Console.WriteLine("Hello");
            }));
        }
    }
}



Anyway, the sure way to find out is to set a breakpoint on your line 12 and see how many times it is called.

This post has been edited by Skydiver: 31 July 2012 - 09:34 AM

Was This Post Helpful? 0
  • +
  • -

#3 adn258   User is offline

  • D.I.C Addict

Reputation: 12
  • View blog
  • Posts: 816
  • Joined: 31-August 11

Re: Why is using WaitAll within a task causing issues?

Posted 31 July 2012 - 10:19 AM

View PostSkydiver, on 31 July 2012 - 09:31 AM, said:

Are you sure it isn't your DoGUIAction() that is doing the duplication?

I'm only seeing one call with this test code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;


namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Task.WaitAll(Task.Factory.StartNew(() =>
            {
                Console.WriteLine("Hello");
            }));
        }
    }
}



Anyway, the sure way to find out is to set a breakpoint on your line 12 and see how many times it is called.


Why would that cause an issue?

  private void DoGUIAction(Action action)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new MethodInvoker(action));
            }
            else
            { action(); }
        }




You have to use the UI thread anyway and I keeps repeating the first file still like I said.. ahhh I don't get that. Only when I use wait with it though not when I don't.
Was This Post Helpful? 0
  • +
  • -

#4 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 7449
  • View blog
  • Posts: 25,091
  • Joined: 05-May 12

Re: Why is using WaitAll within a task causing issues?

Posted 31 July 2012 - 11:19 AM

Okay, instead of a console app, I made a WinForms app. I still don't get any duplicates:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Threading.Tasks;

namespace PopulateListBox
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void DoGUIAction(Action action)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new MethodInvoker(action));
            }
            else
            { action(); }
        }
        
        private void browseButton_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog sf = new OpenFileDialog())
            {
                sf.Multiselect = true;
                sf.Title = "Select Files For Conversion Of The Same File Type Like Images";
                if (sf.ShowDialog() == DialogResult.OK)
                {
                    Task.Factory.StartNew(() =>
                    {
                        foreach (string ifile in sf.FileNames)
                        {
                            DoGUIAction(() => this.myListBox.Items.Add(ifile));
                            Thread.Sleep(5);
                        }
                    });

                }
            }
        }
    }
}


Was This Post Helpful? 0
  • +
  • -

#5 [email protected]   User is offline

  • D.I.C Addict
  • member icon

Reputation: 1003
  • View blog
  • Posts: 975
  • Joined: 30-September 10

Re: Why is using WaitAll within a task causing issues?

Posted 31 July 2012 - 11:39 AM

The first thing that occurred to me was the classic captured iteration variable problem. Try changing your for each loop to this:

foreach (string ifile in sf.FileNames)
{
    string temp = iFile;
    DoGUIAction(() => this.LstBxFilesToConvert.Items.Add(temp));
    Thread.Sleep(5);
}



and see if it makes any difference.

EDIT: Also, there is no need to use Task.WaitAll() as you have got only one Task object. You can use Wait() instead:

Task.Factory.StartNew(() => {
       foreach (string ifile in sf.FileNames) {
                string temp = ifile;
                DoGUIAction(() => this.listBox1.Items.Add(temp));
                Thread.Sleep(5);
       }
}).Wait()


This post has been edited by [email protected]: 31 July 2012 - 12:48 PM

Was This Post Helpful? 1
  • +
  • -

#6 adn258   User is offline

  • D.I.C Addict

Reputation: 12
  • View blog
  • Posts: 816
  • Joined: 31-August 11

Re: Why is using WaitAll within a task causing issues?

Posted 31 July 2012 - 01:11 PM

View Post[email protected], on 31 July 2012 - 11:39 AM, said:

The first thing that occurred to me was the classic captured iteration variable problem. Try changing your for each loop to this:

foreach (string ifile in sf.FileNames)
{
    string temp = iFile;
    DoGUIAction(() => this.LstBxFilesToConvert.Items.Add(temp));
    Thread.Sleep(5);
}



and see if it makes any difference.

EDIT: Also, there is no need to use Task.WaitAll() as you have got only one Task object. You can use Wait() instead:

Task.Factory.StartNew(() => {
       foreach (string ifile in sf.FileNames) {
                string temp = ifile;
                DoGUIAction(() => this.listBox1.Items.Add(temp));
                Thread.Sleep(5);
       }
}).Wait()




Yeah bingo!! Wow dude. You're solution fixed my problem if I wanted to use a listbox +1+1 +1. I'd however like to use the virtual listview which is VERY confusing to me I've been looking at code for it and I still am having issues with even getting it started.
Was This Post Helpful? 0
  • +
  • -

#7 lordofduct   User is offline

  • I'm a cheeseburger
  • member icon


Reputation: 2668
  • View blog
  • Posts: 4,786
  • Joined: 24-September 10

Re: Why is using WaitAll within a task causing issues?

Posted 31 July 2012 - 01:13 PM

Is there a reason you opened a new thread for this when you had one open on the very same topic?
Was This Post Helpful? 1
  • +
  • -

#8 adn258   User is offline

  • D.I.C Addict

Reputation: 12
  • View blog
  • Posts: 816
  • Joined: 31-August 11

Re: Why is using WaitAll within a task causing issues?

Posted 31 July 2012 - 02:55 PM

View Postlordofduct, on 31 July 2012 - 01:13 PM, said:

Is there a reason you opened a new thread for this when you had one open on the very same topic?


I don't have another thread open about this that I know of bro? I'm trying to post here so I don't have to open another thread about listviews which is what I'm curious about now how to use virtual listviews which doesn't seem easy.
Was This Post Helpful? 0
  • +
  • -

#9 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 7449
  • View blog
  • Posts: 25,091
  • Joined: 05-May 12

Re: Why is using WaitAll within a task causing issues?

Posted 31 July 2012 - 03:41 PM

I'm still curious:

And according to Eric Lippert: Closing over the loop variable considered harmful and
Capturing iteration variables

Then why would the behavior not manifest itself here:
Task.Factory.StartNew(() =>
{
    foreach (string ifile in sf.FileNames)
    {
        DoGUIAction(() => this.LstBxFilesToConvert.Items.Add(ifile));
        Thread.Sleep(5);
    }
});


but do so here:
Task.WaitAll(Task.Factory.StartNew(() =>
{
    foreach (string ifile in sf.FileNames)
    {
        DoGUIAction(() => this.LstBxFilesToConvert.Items.Add(ifile));
        Thread.Sleep(5);
    }
}));



And even more interesting is this code I've put together to try to understand what is happening.
This unfortunately doesn't reproduce the problem when I try to run it:
        static void CallMe(Action a)
        {
            a();
        }

        static IEnumerable<int> GetValues()
        {
            for (int i = 0; i < 3; i++)
                yield return i + 1;
        }

        static void MinimalDemo()
        {
            Console.WriteLine("Original Bug minimal example");
            Action[] actions = new Action[3];
            for (int i = 0; i < 3; i++)
                actions[i] = () => Console.WriteLine(i);

            // prints 3, 3, 3
            for (int i = 0; i < 3; i++)
                actions[0]();
        }

        static void Main(string[] args)
        {
            MinimalDemo();

            int[] values = new int[] { 1, 2, 3 };
            Console.WriteLine("Hard values");
            Task.WaitAll(Task.Factory.StartNew(() =>
            {
                foreach (int i in values)
                    CallMe(() => Console.WriteLine(i));
            }));

            Console.WriteLine("Enumerated values");
            Task.WaitAll(Task.Factory.StartNew(() =>
            {
                foreach (int i in GetValues())
                    CallMe(() => Console.WriteLine(i));
            }));
        }


I'm seeing 1, 2, 3 for both the hard coded values and the enumerated values.
Was This Post Helpful? 1
  • +
  • -

#10 adn258   User is offline

  • D.I.C Addict

Reputation: 12
  • View blog
  • Posts: 816
  • Joined: 31-August 11

Re: Why is using WaitAll within a task causing issues?

Posted 31 July 2012 - 03:56 PM

Great information skydiver. And I don't know what to tell you because it definitely causes me the problem but in any case I've decided to try and work on a listview solution to the problem anyway as that's smarter to begin with though confusing me and I never thought about using a listview virtually for this for whatever reason.
Was This Post Helpful? 0
  • +
  • -

#11 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 7449
  • View blog
  • Posts: 25,091
  • Joined: 05-May 12

Re: Why is using WaitAll within a task causing issues?

Posted 31 July 2012 - 04:13 PM

And to add to the weirdness, the following code put into the WinForms program does reproduce the problem:
            this.myListBox.Items.Clear();
            int[] values = new int[] { 1, 2, 3 };
            Task.Factory.StartNew(() =>
            {
                foreach (int i in values)
                    DoGUIAction(() => this.myListBox.Items.Add(i.ToString()));
            });


and
            this.myListBox.Items.Clear();
            int[] values = new int[] { 1, 2, 3 };
            Task.WaitAll(Task.Factory.StartNew(() =>
            {
                foreach (int i in values)
                    DoGUIAction(() => this.myListBox.Items.Add(i.ToString()));
            }));



I wouldn't have expected the first chunck to reproduce the problem because it matches the first chunk of code the OP had, and also the chunk of code I had posted in #4.

I guess for now, I'll just live with it until C# 5.0 comes. Irregardless, hopefully my unit tests will catch errors like this if in case I forget about the capture issue.

Now back to the new topic regarding the Virtual List View: Have you looked at the code at CodeProject: http://www.codeproje...l-Mode-ListView ?
Was This Post Helpful? 0
  • +
  • -

#12 [email protected]   User is offline

  • D.I.C Addict
  • member icon

Reputation: 1003
  • View blog
  • Posts: 975
  • Joined: 30-September 10

Re: Why is using WaitAll within a task causing issues?

Posted 31 July 2012 - 04:36 PM

Here was my take on it:

Spoiler


View PostSkydiver, on 31 July 2012 - 11:13 PM, said:

And to add to the weirdness, the following code put into the WinForms program does reproduce the problem:
            this.myListBox.Items.Clear();
            int[] values = new int[] { 1, 2, 3 };
            Task.Factory.StartNew(() =>
            {
                foreach (int i in values)
                    DoGUIAction(() => this.myListBox.Items.Add(i.ToString()));
            });



I wouldn't have expected the first chunck to reproduce the problem because it matches the first chunk of code the OP had, and also the chunk of code I had posted in #4.


Yes, but that example hasn't got the Thread.Sleep() in it, which is probably serving to give the message pump enough time to process the list box update message before the next iteration (which, if I remember correctly from a previous thread, was exactly the reason that Thread.Sleep() was put there).

Further, I would say that if my theory on the subject is correct, if you replaced BeginInvoke() with Invoke() in the DoGUIAction() method, and took out the Thread.Sleep() in the for each loop, it should produce the correct output because Invoke() doesn't return until the posted message has been processed.

In this code,

this.myListBox.Items.Clear();
int[] values = new int[] { 1, 2, 3 };
Task.WaitAll(Task.Factory.StartNew(() =>
{
    foreach (int i in values)
        DoGUIAction(() => this.myListBox.Items.Add(i.ToString()));
}));


by using Task.WaitAll(), the UI thread will be blocked, meaning none of the list box update messages will be processed until the task (and, more importantly, the for each loop) has finished), so every update to the list box will be done with the last value of the iteration variable, hence giving the wrong output.

This post has been edited by [email protected]: 31 July 2012 - 04:44 PM

Was This Post Helpful? 2
  • +
  • -

#13 adn258   User is offline

  • D.I.C Addict

Reputation: 12
  • View blog
  • Posts: 816
  • Joined: 31-August 11

Re: Why is using WaitAll within a task causing issues?

Posted 31 July 2012 - 04:52 PM

That's true I forgot about the .wait() that you can place at the end like you did in any case I'm confused about listviews now so I'd like to talk about that sometime no offense either here or in another topic? I understand essentially what was wrong with my last code and why it wasn't working (though confusing) I'm glad I understand that. I know this might seem a little simpler but listviews are bugging me to death. Let's say you create two columns below like so. I've tried a million methods like insert etc. etc. how can you add an item or a range of items TO JUST THE COLUMN you want.

Using my example below lets say I wanted to add Los Angeles To the top (I'm assuming 0 index) of the Place Column. How would I go about doing that? I've tried a million things mind you

listView1.View = View.Details;
            listView1.Columns.Insert(0, "Time", "Time", 100, HorizontalAlignment.Left, 0);
            listView1.Columns.Insert(1, "Place", "Place", 100, HorizontalAlignment.Left, 0);
            



Was This Post Helpful? 0
  • +
  • -

#14 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 7449
  • View blog
  • Posts: 25,091
  • Joined: 05-May 12

Re: Why is using WaitAll within a task causing issues?

Posted 31 July 2012 - 05:25 PM

Wow! Your fast! For me to try a million things, it would take at least a few weeks.

Anyway, did you look at the documentation? ListView.Items perhaps: http://msdn.microsof....listview.items

This post has been edited by Skydiver: 31 July 2012 - 05:34 PM

Was This Post Helpful? 0
  • +
  • -

#15 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 7449
  • View blog
  • Posts: 25,091
  • Joined: 05-May 12

Re: Why is using WaitAll within a task causing issues?

Posted 31 July 2012 - 05:30 PM

Or even better straight from MSDN's ListView overviews: How to: Add and Remove Items with the Windows Forms ListView Control
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2