Limited concurrency TaskScheduler blocks itself

I am trying to use the following custom task scheduler to limit concurrent web requests:

I use it like this:

const int CONCURRENCY_LEVEL = 2;

static void Main()
{
    TaskFactory factory = new TaskFactory(new LimitedConcurrencyLevelTaskScheduler(CONCURRENCY_LEVEL));

    Task.WaitAll(new[] { factory.StartNew(() => SomeAction("first")), factory.StartNew(() => SomeAction("second")) });

    Console.WriteLine("All tasks ended");        
    Console.Read();
}

static void SomeAction(string task)
{
    Console.WriteLine(task + " task started");
    Console.WriteLine(AnotherTask(task).Result);
    Console.WriteLine(task + " task ended");
}

static async Task<string> AnotherTask(string task)
{
    return await Task.Run(() =>
    {
        Console.WriteLine(task + " inner task started");
        // imitate web requests
        Thread.Sleep(200);
        Console.WriteLine(task + " inner task ended");
        return "ok";
    });
}

The problem is that internal tasks use mine LimitedConcurrencyLevelTaskSchedulerinstead of the standard one TaskScheduler. This leads to self-locking, and the output is as follows:

second task started
first task started
first inner task started
second inner task started
second inner task ended
first inner task ended

When I change CONCURRENCY_LEVELto 3or change factoryto Task.Factory, then, obviously, everything works fine, and the result is as follows:

first task started
second task started
first inner task started
second inner task started
second inner task ended
first inner task ended
ok
second task ended
ok
first task ended
All tasks ended

I cannot change the code in SomeAction. What else can I do? Is there a bug in the Microsoft sample?

+4
2

TaskCreationOptions.HideScheduler :

Task.WaitAll(new[] 
{
   factory.StartNew(() => SomeAction("first"),  TaskCreationOptions.HideScheduler), 
   factory.StartNew(() => SomeAction("second"), TaskCreationOptions.HideScheduler)
});

MSDN:

HideScheduler . , , StartNew ContinueWith, , Default .

+6

Try

static async Task<string> AnotherTask(string task)
{
    return await Task.Run(() =>
    {
        Console.WriteLine(task + " inner task started");
        // imitate web requests
        Thread.Sleep(200);
        Console.WriteLine(task + " inner task ended");
        return "ok";
    }).ConfigureAwait(false); //<--------
}
+2

All Articles