Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why this task hangs?

Tags:

c#

task

[TestMethod]
public void Y()
{
    int i = 0;
    new Task(() => i++).Wait();

    Assert.AreEqual(1, i);
}

For what reason is the Task in the above example waiting forever? How should I Wait() for the Task so it does not hang?

like image 229
Mirek Avatar asked Dec 30 '25 21:12

Mirek


2 Answers

You did not start the Task. Try this:

[TestMethod]
public void Y()
{
    int i = 0;
    Task task = new Task(() => i++);
    task.Start();
    task.Wait();
    Assert.AreEqual(1, i);
}

or even better (as Damien suggested) use Task.Run():

[TestMethod]
public void Y()
{
    int i = 0;
    Task.Run(() => i++).Wait();
    Assert.AreEqual(1, i);
}
like image 183
René Vogt Avatar answered Jan 02 '26 11:01

René Vogt


There are generally 3 reasons why someTask.Wait "hangs":

  1. You've deadlocked the synchronization context that was captured
  2. There is no synchronization context at all
  3. You're waiting for a task that is never started

In the first example, windows forms applications would be a likely scenario but the [TestMethod] attribute tells a different story. You can get out of this mess however by using .ConfigureAwait(false) but before going down this route please read up on the subject. async/await looks easy on the surface but you're treading into a minefield.

In unit test projects you need a test runner that processes messages posted to the synchronization context. This could be a likely problem if you're using a test runner that does not.

However, in your current method you're not starting the task. A task never started never completes.

However, if you start the task you might end up with point 2 above.

Conclusion: Make sure you start your task, and if that still blocks take a look at the unit test framework you're using.

To start the task:

var task = new Task(() => i++);
task.Start();
task.Wait();

Also, in general unless you build some kind of framework around handling tasks you should probably not use new Task(...) at all but instead opt for Task.Run:

Task.Run(() => i++).Wait();

If your test runner supports async/await properly I would rather rewrite the entire method to be async:

[TestMethod]
public async Task Y()
{
    int i = 0;
    await new Task(() => i++);

    Assert.AreEqual(1, i);
}
like image 22
Lasse V. Karlsen Avatar answered Jan 02 '26 12:01

Lasse V. Karlsen