2

Consider the following code:

Task task1;
Task task2;
private void button1_Click(object sender, EventArgs e)
{
    task1 = Task.Run(() =>
    {
        for (int i = 0; i < 100000; i++)
        {
            BeginInvoke(new Action<int>((int n) =>
            {
                listView1.Items.Add(n.ToString());
            }), i);
        }
    });            
    task2 = task1.ContinueWith(t =>
    {
        MessageBox.Show("Why isn't this reached");
    }, TaskScheduler.FromCurrentSynchronizationContext());
}

private void button2_Click(object sender, EventArgs e)
{
    MessageBox.Show(String.Format("task1 status:{0}\r\ntask2 status:{1}", task1.Status, task2.Status));
}

If I run this on Windows 8, .NET Framework 4.5.2, I get the follwing output when I click button2:

task1 status:RanToCompletion

task2 status:WaitingToRun

How is this possible even though I used ContinueWith?

I know that BeginInvoke just enqueues the delegate for execution, if I use Invoke it works just fine. Is this a bug or is it interfering with BeginInvoke? Any ideas? Thanks in advance.

juharr
  • 31,741
  • 4
  • 58
  • 93
hl3mukkel
  • 5,369
  • 3
  • 21
  • 21
  • You are flooding the message queue, maybe you need to wait longer till you hit button2, don't click it till you see 100000 in the listblox. Does it work then? – Scott Chamberlain Jan 04 '16 at 18:55
  • Nope it has nothing to do with that, task2 never gets called.However, if I use a slower upper bound for i like 100 instead of 100000, it gets called just fine. Could it be that the windows message pump is overloaded? it does add all the 100000 items however, which is pretty weird.. – hl3mukkel Jan 04 '16 at 18:56

1 Answers1

1

I don't have a primary source, but this post states that the message queue has a limit of 10,000 records(Hans Passant is one of the most experts on this site for windows forms so I trust his word that the limit exists).

Because you are putting 100,000 records on there it is either pushing your ContinueWith off the stack or never getting added there in the first place (I am not sure which)

Community
  • 1
  • 1
Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431
  • All items are added however, if it were to put records offlimit, how can they all be executed anyway? – hl3mukkel Jan 04 '16 at 18:59
  • The message queue has a limit of 10000, I see that, but all the items added through BeginInvoke are added anyway, so the message queue doesn't seem to be the limiting factor. Are you sure that Task.FromCurrentSyncronizationContext is implemented through a windows message? Thanks for the other post though, will take a look at it. – hl3mukkel Jan 04 '16 at 19:02
  • I think I know, There are two queues, a invoke queue and a message queue. Every call to BeginInvoke adds a delegate to the invoke queue and a "Process the invoke queue" message to the message queue. The invoke queue has no limit, the message queue has a 10,000 limit. So what happens is you fill the message queue with 10,000 "process" messages and your continue with never gets a chance to be put on (or gets pushed off of, still not sure which happens) the message queue. After the first "process" is done the invoke queue is empty but it still goes through the other 9,999 process messages. – Scott Chamberlain Jan 04 '16 at 19:05
  • And yes, I am sure `Task.FromCurrentSyncronizationContext` uses a windows message, that is the only way to get something to get queued to run on the UI thread in WinForms. – Scott Chamberlain Jan 04 '16 at 19:10
  • I agree on the seperate queues, however if every call to BeginInvoke would add a delegate to the invoke queue and a "process invoke" message to the message queue, there wouldn't be more than 10000 items added would there? BeginInvoke is not syncronous, as in it only adds the delegate to a/ multiple queues as you said, but I don't understand how all 100 000 items are added, yet the ContinueWith failed somehow. – hl3mukkel Jan 04 '16 at 19:11