3

I'm facing a weird bug. I have something like 100 long running tasks and I want to run 10 of them in the same time.

I found something very similar to my need here : http://msdn.microsoft.com/en-us/library/hh873173%28v=vs.110%29.aspx in the Throttling section.

Here the C# code after simplification :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    public class Program
    {
        static void Main(string[] args)
        {
            Test();
        }

        public static async void Test()
        {
            var range = Enumerable.Range(1, 100).ToList();

            const int CONCURRENCY_LEVEL = 10;
            int nextIndex = 0;
            var matrixTasks = new List<Task>();

            while (nextIndex < CONCURRENCY_LEVEL && nextIndex < range.Count())
            {
                int index = nextIndex;
                matrixTasks.Add(Task.Factory.StartNew(() => ComputePieceOfMatrix()));
                nextIndex++;
            }

            while (matrixTasks.Count > 0)
            {
                try
                {
                    var imageTask = await Task.WhenAny(matrixTasks);
                    matrixTasks.Remove(imageTask);
                }
                catch (Exception e)
                {
                    Console.Write(1);
                    throw;
                }

                if (nextIndex < range.Count())
                {
                    int index = nextIndex;
                    matrixTasks.Add(Task.Factory.StartNew(() => ComputePieceOfMatrix()));
                    nextIndex++;
                }
            }

            await Task.WhenAll(matrixTasks); 
        }

        private static void ComputePieceOfMatrix()
        {
            try
            {
                for (int j = 0; j < 10000000000; j++) ;
            }
            catch (Exception e)
            {
                Console.Write(2);
                throw;
            }
        }
    }
}

When running it from a Unit Test a have a ThreadAbortException in ComputePieceOfMatrix.

Do you have any idea ?

Edit :

According to a comment, I tried this :

static void Main(string[] args)
{
    Run();
}

private static async void Run()
{
    await Test();
}

public static async Task Test()
{
    var range = Enumerable.Range(1, 100).ToList();

But it's exactly the same.

3 Answers3

2

1.Your code causes exception

try
{
    for (int j = 0; j < 10000000000; j++) ;
}
catch (Exception e)
{
    Console.Write(2);
    throw;
}

Just a simple OverflowException becase 10000000000 - is long and j counter int.

2.Your main tread is exiting before child threads run to finish. Most likely you are getting ThreadAbortException because Threads are closed by runtime

3.await Test() - correctly just call Test(), and await Task.WhenAny without await as well

Regfor
  • 8,515
  • 1
  • 38
  • 51
  • Wow... yes you're right with the test code. But in my real code it's not the same reason... I'm actually calling a webservice. Now I'll have to find a small code that crash just like my real code crash, BUT without a stupid mistake like that... Thank you ! – Guillaume Philipp Feb 27 '14 at 13:51
  • Yup, and var imageTask = await Task.WhenAny(matrixTasks); await is not correct there. Just without await here as well, because your execution flow will be broken. – Regfor Feb 27 '14 at 14:00
  • It has to be broken, otherwise I'll have more than 10 tasks running at the same time. – Guillaume Philipp Feb 27 '14 at 15:03
1

Change the return type of Test() to Task, then wait for that Task to finish before your program reaches the end.

static void Main(string[] args)
{
    Test().Wait();
}

public static async Task Test()
{
    // ...
}
Steven Liekens
  • 13,266
  • 8
  • 59
  • 85
0

I would change your Test from a void to a Task return type and in the main method I would do in place of Test();

Task t = Test();
t.Wait();
TYY
  • 2,702
  • 1
  • 13
  • 14