1

Closed

OutputAvailableAsync doesn't work for AsyncProducerConsumerQueue

description

I've installed "Async and Task helpers" v.2.1.3 through nuget to my Windows Phone 8 project and I wanted to use AsyncProducerConsumerQueue as a simple task queue like the following.
        internal TaskQueue()
        {
            Task.Factory.StartNew(() => ProcessQueue(), TaskCreationOptions.LongRunning);
        }

        private async Task ProcessQueue()
        {
            while (await queue.OutputAvailableAsync())
            {
                Func<Task> command = queue.Dequeue();
                try
                {
                    command().Wait();
                }
                catch (Exception ex)
                {
                    // Exceptions from your queued tasks will end up here.
                    //throw;
                }
            }
        }

        internal void Enqueue(Func<Task> command)
        {
            queue.Enqueue(command);
        }
The problem is that it does not work. I have isolated the issue with the OutputAvailableAsync. Even if I do not queue any task, the following message error is displayed when I'm Debugging using a device:
The network connection to 127.0.0.1:8016 has been lost. Debugging will be aborted.
Even stranger is that, if I try it again to run it in Debug Device mode, it displays the error that the application is not installed or that the screen is locked on the device, when clearly that is not the case.

To get around I have to go to the device, manually uninstall the application and redeploy it .

If I try to run the application manually in the device, it will lock in the loading stage.

Do you have any idea what the problem might be?
If not possible to figure it out, could there be a way of achieving the same result, a task queue in WP8, not using Nito Async Ex?
Closed Jan 12, 2014 at 11:54 AM by StephenCleary

comments

StephenCleary wrote Dec 30, 2013 at 10:20 PM

I'm not able to reproduce this.

I created a new Windows Phone App project, added a reference to Nito.AsyncEx 2.1.3, and pasted in the code you had (moving the Task.Factory.StartNew line to the MainPage constructor). I then added this line of code:
private AsyncProducerConsumerQueue<Func<Task>> queue = new AsyncProducerConsumerQueue<Func<Task>>();
And it compiled, deployed to the emulator, and ran just fine.

I then added a "producer" task by putting the following code after the Task.Factory.StartNew line:
Task.Run(() =>
{
    Thread.Sleep(1000);
    Enqueue(async () => { await Task.Yield(); Debug.WriteLine("At 0"); });
    Thread.Sleep(1000);
    Enqueue(async () => { await Task.Yield(); Debug.WriteLine("At 1"); });
    Thread.Sleep(1000);
    Enqueue(async () => { await Task.Yield(); Debug.WriteLine("At 2"); });
});
And I could see the expected output in my Output window, at 1 second intervals:
At 0
At 1
At 2

This indicates the AsyncProducerConsumerQueue is working fine.

I suspect the problem may be elsewhere in the code. In this example code, you're mixing asynchronous and blocking code, which is usually not a good idea. In particular, the "command().Wait();" is very odd considering it's in an async method; I would write this as "await command();" instead. In some situations, you may see deadlocks when you mix asynchronous and blocking code (http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html, http://blog.stephencleary.com/2012/12/dont-block-in-asynchronous-code.html).

Since you mention the app locks up during loading (which I suspect may also cause the debugger connection to fail), I suspect you may be calling Wait or Result from a page or viewmodel constructor. If this is the case, I recommend you consider using the NotifyTaskCompletion types in AsyncEx which were designed to handle this scenario.

However, if you're sure the problem is with the AsyncProducerConsumerQueue, please try to create a minimal project that reproduces the problem and I'll try to duplicate it again. There are no built-in asynchronous queues on WP8 (or blocking queues, for that matter); you'd have to build them yourself (e.g., http://blog.stephencleary.com/2012/12/async-producer-consumer-queue-2-more.html).

P.S. LongRunning doesn't actually do anything in this code. I'd replace the Task.Factory.StartNew call with Task.Run (see http://blog.stephencleary.com/2013/08/startnew-is-dangerous.html).