Async Await Loop/Math problems

I'm making a little program to practice with WPF and Async/Await for multithreading, and what the program does is:

  1. Find all the prime numbers between two numbers "a" and "b", and spit them out to a textbox called "Prime1".
  2. Simultaneously in a different task, find all the prime numbers between "c" and "d", and spit them out to a textbox called "Prime2".
  3. A button in the window will allow the user to click it, and it will keep track of how many times it has been clicked, whilst the other two tasks find prime numbers, to demonstrate asynchronous operations.

The code is as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WPF_Asynch_Project
{
    public partial class MainWindow : Window
    {
        public int ClickAmount = 0;
        public MainWindow()
        {
            InitializeComponent();
            DelegationIsAwesome();
        }

        private void Test_Click(object sender, RoutedEventArgs e)
        {
            ClickAmount++;
            MessageBox.Show("You clicked me " + ClickAmount.ToString() + " times!");
        }

        private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
        }

        private async void DelegationIsAwesome()
        {
            Task enumtask = new Task(() => FindPrimes(100000, 100000000));
            Task[] enumall = new Task[2];
            enumall[0] = enumtask;
            enumall[1] = new Task(() => FindPrimes2(1000, 10000));
            enumall.ToList().ForEach(t => t.Start());
            await Task.WhenAll(enumall).ConfigureAwait(false);
        }

        private void FindPrimes(long lower, long upper)
        {
            for (long i = lower; i < upper; i++)
            {

                long primeornot = 1;
                for (long q = 2; q < i; q++)
                {
                    if (i % q == 0)
                    {
                        primeornot = 0;
                    }
                }
                if (primeornot == 1)
                {
                    System.Threading.Thread.Sleep(6);
                    Prime1.Dispatcher.BeginInvoke(
                        (Action)(()=>{ Prime1.Text += i.ToString() + ", "; }));
                }
            }
        }

        private void FindPrimes2(int lower, long upper)
        {
            for (int i = lower; i < upper; i++)
            {
                int primeornot = 1;
                for (int q = 2; q < i; q++)
                {
                    if (i % q == 0)
                    {
                        primeornot = 0;
                    }
                }
                if (primeornot == 1)
                {
                    System.Threading.Thread.Sleep(5);
                    Prime2.Dispatcher.BeginInvoke(
                        (Action)(() => { Prime2.Text += i.ToString() + ", "; }));
                }
            }
        }
    }
}

However I get odd results. The following is a picture from the program:

enter image description here

Obviously the output from the prime-finding methods is incorrect. But why does it keep repeating those same numbers? It also sometimes spits out a number equal to UpperBound even though "i" should never equal or be greater than UpperBound.

What is happening to my output, and how do I fix it?

Jon Skeet
people
quotationmark

This has nothing to do with async/await, really.

You're calling BeginInvoke here:

Prime1.Dispatcher.BeginInvoke(
    (Action)(()=>{ Prime1.Text += i.ToString() + ", "; }));

... and your lambda expression uses i, which means it will append the current value of i when the delegate executes. That's not necessarily the value of i when you call BeginInvoke.

If you want to capture the value (rather than the variable) you basically need to instantiate a new variable each time. You might as well do the conversion to a string:

string textToAppend = i + ", ";
// No need for braces here...
Prime1.Dispatcher.BeginInvoke((Action)(() => Prime1.Text += textToAppend));

Because you've declared the variable textToAppend inside the loop, each iteration will create a delegate capturing a separate variable.

You need to do this in both of your methods.

people

See more on this question at Stackoverflow