Am I using Task correctly?

JohnHJohnH GBMember ✭✭✭✭✭

Im updating my app to be Task based rather than have a Queue and a single thread that services requests on that queue.

What Im doing is on the UI thread I create a task with an action, that start that task. The action of that task will eventually invoke a delegate that will attempt to update the UI, all wrapped nicely in an InvokeOnMainThread. However, Im finding that any code inside the invoke is not being run, and my app just hangs.

Code in the UI thread, inside a generic class I created called Publisher:
Task newTask = new Task(() => SubscriberAdded(sub));

The SubscriberAdded method loads some data in a thread safe manner, then invokes a delegate event that in turn will attempt to invoke on the UI thread to refresh some controls.

Am I using Task correctly? This all looks fairly simple, I don't see why this wouldn't or shouldn't work. I am not using any await code here.

Thanks
John

Posts

  • adamkempadamkemp USInsider, Developer Group Leader mod

    You may need to show more code. How are you using that task? Are you starting it? How are you waiting for it? What does the code inside the task look like?

    From the description of how you're doing InvokeOnMainThread I think you may be overthinking it. Try something like this:

    private async Task Foo()
    {
        await Task.Run(() => SubscriberAdded(sub));
        // Do stuff after that finishes
    }
    

    Task.Run will schedule that action on some background thread, and the "await" keyword handles all of the glue code to basically pause that function (freeing up the UI thread) and resume it when the task is completed.

  • JohnHJohnH GBMember ✭✭✭✭✭
    edited February 2014

    Maybe I am using it in the wrong way, my code for this is really simple:

    <br /> sub = new Subscriber(<br /> ()=> <br /> {<br /> Console.WriteLine("UpdateUI 1");<br /> InvokeOnMainThread(() =><br /> {<br /> Console.WriteLine("UpdateUI 2");<br /> });<br /> } );</p> <pre><code> Task newTask = new Task(() => SubscriberAdded(sub)); newTask.Start();

    I don't await as I don't want to wait until the task finishes, I want the UI to continue to respond. The code in SubscriberAdded(sub) will fetch data and eventually InvokeOnMainThread with the results.
    The same thing could be achieved by getting a new thread from the thread pool, but I was under the impression that Tasks were the way to go.

    EDIT: Ive updated it with example delegate code attached to the Subscriber class. "UpdateUI 2" is never hit, but "UpdateUI 1" is.

  • JohnHJohnH GBMember ✭✭✭✭✭

    Ok, erm, well, I...
    I converted it to use a ThreadPool and was getting the same results, so I ramped up the number of subscribers and could see the thread count going up, obviously a deadlock! Found it, all good now.

    I prefer using a Task object instead of ThreadPool.QueueUserWorkItem, even in this simple example where async and await aren't required. Any reason not to?

    Cheers!
    John

  • SKallSKall USMember ✭✭✭✭

    Consider using ViewModel updates instead of updating the UI from the task itself. I just created an example that should be easy to follow.

    ViewModel implemented in PCL library (so it can be reused with Android, WP8 etc):
    https://github.com/sami1971/SimplyMobile/blob/master/Core/Samples/SimpleViewModel.Core/MyViewModel.cs

    iOS client with CancellationToken (good to have if you are leaving UI functional):
    https://github.com/sami1971/SimplyMobile/blob/master/iOS/Samples/SimpleViewModel/SimpleViewModelViewController.cs

    You can run the sample if you download the project and open the iOS solution from iOS\SimplyMobile.iOS.sln

Sign In or Register to comment.