4

I'm having a hard time understanding async and the corresponding behavior. This is a model of the program I'm trying to write, and a repro of the problem I'm having:

namespace AsyncTesting
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("starting....");
            MyClass myClass = new MyClass();
            myClass.DoSomeWork();
            Console.WriteLine("ending....");
            Console.ReadLine();
        }
    }

    class MyClass
    {
        public bool DoSomeWork()
        {
            return GetTrue().Result;
        }

        Task<bool> GetTrue()
        {
            return new Task<bool>(() => true);
        }
    }
}

When I make the GetTrue().Result call, it never returns. My Task<bool> GetTrue() method is a dummy method for repro purposes, but I'm not quite sure why it never comes back. But it returns if I have this:

namespace AsyncTesting
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("starting....");
            MyClass myClass = new MyClass();
            myClass.DoSomeWork();
            Console.WriteLine("ending....");
            Console.ReadLine();
        }
    }

    class MyClass
    {
        public async void DoSomeWork()
        {
            await GetTrue();
        }

        Task<bool> GetTrue()
        {
            return new Task<bool>(() => true);
        }
    }
}

The problem is, with my repro I want the initial behavior. I don't want async void for the calling method. I want to be able to return bool from my calling "normal" method. How can I achieve this? How can I get the first example to run and actually return the bool from DoSomeWork()?

Thank you in advance.

EDIT: Thank you for the answers. I think what the problem is, is that my GetTrue() method isn't a true repro. In my method, I'm not generating the actual Task<bool> object. It's really a call to Task.Factory.FromAsync<bool>() that is creating the Task<bool> object. And it's that task that I don't know how to "start". Any other ideas? Thanks!

5
  • Your edit changes the concept of the question. If you're trying to block (with task.Result) on the result of FromAsync, you'd need to clarify what is the actual context of this code. Is it really a simple console app, or perhaps, it is a WinForms / WPF / ASP.NET app? Then it might explain why are you're having a deadlock. Check Stephen Cleary's blog: blog.stephencleary.com/2012/07/dont-block-on-async-code.html Commented May 12, 2014 at 11:57
  • @Noseratio Sorry, the context is a WCF service. The Task.Factory.FromAsync<bool>() call is wrapping the Begin...() and End...() functions that the service has pushed to the consumer. But I see no way to actually start the task and it just hangs. Commented May 12, 2014 at 12:47
  • So this is still the client-side where you call a WCF service? If so, it still matters what kind of app is this client-side app. Commented May 12, 2014 at 12:52
  • @Noseratio That's correct, it is the client-side making the WCF call. The client-side app is a Windows Phone 8 application. Commented May 12, 2014 at 12:55
  • This is a frequent mistake, I've updated my answer with more details about it. Commented May 12, 2014 at 13:14

2 Answers 2

4

You're probably looking for:

Task<bool> GetTrue()
{
    return Task.FromResult(true);
}

instead of:

Task<bool> GetTrue()
{
    return new Task<bool>(() => true);
}

In the latter case, you don't even start the task you create. You'd need to start it with Task.Run or Task.RunSynchronously. Usually you don't create tasks directly via new Task(). Check Stephen Toub's "Task.Factory.StartNew" vs "new Task(...).Start" and "Task.Run vs Task.Factory.StartNew".

Depending on what you're trying to achieve, you might be tempted to do this:

Task<bool> GetTrue()
{
    return Task.Run(() => true);
}

However, usually this turns to be a known-anti-pattern, check "Should I expose asynchronous wrappers for synchronous methods?".

Updated to address the comments:

... the context is a WCF service. The Task.Factory.FromAsync() call is wrapping the Begin...() and End...() functions that the service has pushed to the consumer. But I see no way to actually start the task and it just hangs. ... it is the client-side making the WCF call. The client-side app is a Windows Phone 8 application.

You're experiencing a deadlock on the UI thread, because you're blocking on the result of a pending task (with task.Result). The task itself cannot be completed, because the await continuation is posted asynchronously to the dispatcher loop of the UI thread of your WP8 app, which is now blocked. Stephen Cleary explains this in great details in his blog. To avoid this, you should embrace "async all the way down" programming model. It practically means that you should make your UI event and command handlers async as well, and do var result = await task, rather than var result = task.Result in there.

Sign up to request clarification or add additional context in comments.

5 Comments

+1 for the anti-pattern. Stephen Cleary also has a nice blog post on this IIRC. It basically says "let consumers of your API wrap things in Tasks.. don't do it yourself".
Thank you for the answer! (Please see my answer edit) I'm not actually creating the Task<bool> (apologies, bad repro I believe). The Task<bool> is getting generated from a call to Task.Factory.FromAsync<bool>(). And it's that task that I'm not sure how to "start". Any thoughts? Thanks in advance! Also, +1.
@user3175663, see my comment to the question.
Ok perfect, I'll try that. With async event handlers, though, I thought async void was bad practice. Am I mistaken?
@user3175663, async void event handlers are probably the most notable exception of that rule, check this. Just deal properly with exceptions and reentracy inside async void event handlers.
2

You need to start a task before it does anything.. calling Run will do that for you:

Task<bool> GetTrue()
{
    return Task.Run(() => true);
}

This gives the output you expect. Result is a blocking call. If your Task instance never starts.. Result can never return.

1 Comment

Thank you for the answer! (Please see my answer edit) I'm not actually creating the Task<bool> (apologies, bad repro I believe). The Task<bool> is getting generated from a call to Task.Factory.FromAsync<bool>(). And it's that task that I'm not sure how to "start". Any thoughts? Thanks in advance! +1.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.