Miroslav
Miroslav

Reputation: 4695

Why this task hangs?

[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?

Upvotes: 3

Views: 333

Answers (2)

René Vogt
René Vogt

Reputation: 43886

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);
}

Upvotes: 9

Lasse V. Karlsen
Lasse V. Karlsen

Reputation: 391406

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);
}

Upvotes: 4

Related Questions