0

I'm attempting to create an async method which returns data from an event, or times out (and returns null). The code below loosely follows suggestions from other threads.

public async Task<Data> GetNextData(TimeSpan timeout)
        {
            var tcs = new TaskCompletionSource<Data>();

            //setup event handler
            var onEvent = new EventHandler<Data>((sender, args) =>
            {
                tcs.SetResult(args);
            });

            OnDataReceived += onEvent;

            //await result from handler or timeout
            Data result = null;

            if (await AwaitWithTimeout(tcs.Task, timeout))
            {
                result = tcs.Task.Result;
            }

            //cleanup
            OnDataReceived -= onEvent;

            return result;
        }

        private static async Task<bool> AwaitWithTimeout(Task task, TimeSpan timeout)
        {
            return await Task.WhenAny(Task.Delay(timeout), Task.Delay(timeout)) == task;
        }

The problem appears to be in AwaitWithTimeout, which should complete when either the task or the timeout complete. Instead, it never stops waiting. What I found strange is that, even when I replaced the contents of this method with something like await Task.Delay(timeout), it would never finish.

The following shows how I call it from the outer scope:

var foo = channel.GetNextData(TimeSpan.FromSeconds(5));
SendDataRequest();
foo.Wait();

Why does this code never complete?

brightbulb
  • 11
  • 3
  • 1
    You are deadlocking your code. You should never mix async/await with `Task.Wait()` or `Task.Result`, lots of duplicates. If you throw a `.ConfigureAwait(false)` on each of your `await` it may fix it, but the better solution is to not use `.Wait()` or `.Result` (`result = tcs.Task.Result;` can be replaced with `result = await tcs.Task;`, there is no penalty on awaiting a task that is already complete) – Scott Chamberlain Jun 16 '16 at 02:25
  • Could you elaborate? Why should I avoid mixing those calls? – brightbulb Jun 16 '16 at 02:29
  • 1
    Read the linked duplicate. Also see [this article](https://msdn.microsoft.com/en-us/magazine/jj991977.aspx) from the MSDN, you are violating the "Async all the way" principal. Also read the blog post "[Don't Block on Async Code](http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html)" by the same author. – Scott Chamberlain Jun 16 '16 at 02:30
  • Thanks. I'll investigate both now. – brightbulb Jun 16 '16 at 02:32

0 Answers0