none
Issue with Task RRS feed

  • Question

  • Hi,

    I am using the following code with Form application under an async method.

    var a = Task.Run(async () => await Get_iSeeLoc_Real_Locations()).Result;

    I would expect the UI not to be in a deadlock during this line. The Get_iSeeLoc_Real_Locations() is an async method as well.

    I can also see in the thread window that not new thread was invoked.

    Your help will be greatly appreciated.

    Thanks
    Sharon

    Wednesday, December 4, 2019 8:24 PM

Answers

  • Hi,

    I am getting the exactly same issue.

    Is it possible that the issue shows up since the caller is not the UI, it is called by a method that is triggered by a timer under the UI.

    See below.

    public void timerSoldiersLocationUpdate_Tick(object sender, EventArgs e) { timerSoldiersLocationUpdate.Stop(); . . . Get_iSeeLoc_Locations(); .//(Shouldn't get here till the computation is finished)

    . . timerSoldiersLocationUpdate.Start(); }


    Thanks

    Sharon

    • Marked as answer by SZohar Thursday, December 5, 2019 11:46 PM
    Thursday, December 5, 2019 9:13 PM

All replies

  • Try one of these:

    var a = await Get_iSeeLoc_Real_Locations( );

    var a = await Get_iSeeLoc_Real_Locations( ).ConfigureAwait( false );

    var a = await Task.Run( async ( ) => await Get_iSeeLoc_Real_Locations( ) );

     


    • Edited by Viorel_MVP Wednesday, December 4, 2019 8:53 PM
    Wednesday, December 4, 2019 8:53 PM
  • Thanks for you answer.

    When trying this option var a = await Get_iSeeLoc_Real_Locations( ).ConfigureAwait( false ); The GUI was still in deadlock.

    When trying var a = await Task.Run( async ( ) => await Get_iSeeLoc_Real_Locations( ) ); The GUI was finally released from the deadlock but the await didn't happen as expected since it will go out from the method and mess the sequence that needs to be in sync, it will get to the next line of code once in a while.

    When trying the await Get_iSeeLoc_Real_Locations( ); the GUI is still in deadlock.

    The method in general is

       

    public async void Get_iSeeLoc_Locations()

    {

                S1.Start();
                 var a = await Get_iSeeLoc_Real_Locations();

                    S1.Stop();
                    Infrastructure.Print_To_Console("Calc Location thread took " +a.ToString()+"-"+ S1.ElapsedMilliseconds.ToString() + " MS");

    }

    The Get_iSeeLoc_Real_Locations method is very computation intensive that can take over 20 seconds, I want to GUI to continue being responsive during this time.

    Your help is appreciated.

    Sharon


    Wednesday, December 4, 2019 10:09 PM
  • Hi SZohar,
    When you use the task.result property, it will block the current thread and wait until the task is finished. So the GUI is in deadlock in that period.
    You can define a method to get the result and then use the method Task.ContinueWith to call this method.
    Here is a code example and you can refer to it.
    private void button1_Click(object sender, EventArgs e)
    {
        var cts = new CancellationTokenSource();
        var ct = cts.Token;
        Task<Int32> task = new Task<Int32>(n => TaskTest(10, ct), 0);
        task.Start();
      //var i = task.Result;
      //Console.WriteLine(i);
        Task tsk = task.ContinueWith(t => ShowResult(t));
    }
    private int TaskTest(int num, CancellationToken token)
    {
        // num = 0;
        for (int i = 0; i < int.MaxValue - 10; i++)
        {
            token.ThrowIfCancellationRequested();
            num++;
        }
        return num;
    }
    private void ShowResult(Task<Int32> t)
    {
        try
        {
            MessageBox.Show(t.Result.ToString());
        }
        catch (AggregateException ex)
        {
            MessageBox.Show("Operation interrupted");
        }
    }
    Best Regards,
    Daniel Zhang

    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, December 5, 2019 9:46 AM
  • In addition to what Daniel said about Result/Wait blocking the thread (even a UI thread) I'd also like to say that calling an async method inside Task.Run is redundant. The purpose of Task.Run is to run sync code async. If you have an async method then you don't need Task.Run.

    var a = await Get_iSeeLoc_Real_Locations();
    Interestly, if the calling method is async then this won't block the UI thread because the await triggers a return of the method which allows the UI thread to continue. Since you're not using `ConfigureAwait` the rest of this method will execute on the UI thread after the async method returns.


    Michael Taylor http://www.michaeltaylorp3.net

    Thursday, December 5, 2019 3:06 PM
    Moderator
  • Thank you guys for your inputs.

    As recommended I implemented the following:

    public async void Get_iSeeLoc_Locations()

    {

    .....

    Stopwatch S1 = new Stopwatch();

    S1.Start(); Task<bool> task = new Task<bool>(n => Get_iSeeLoc_Real_Locations(),0); task.Start(); Task<string> tsk = task.ContinueWith(t => Print_Time()); S1.Stop(); Infrastructure.Print_To_Console("Calc Location thread took " + "-"+ S1.ElapsedMilliseconds.ToString() + " MS");

    }


    As before I can see the task starts but don't wait to the task.ContinueWith.

    I do see that when the Get_iSeeLoc_Real_Locations is completed the program will go back and run the code after the Continue with. The problem is that since the sequence continued before the continueWith was completed the data is totally out of sync.

    I am also getting a warning under the method name that method lacks await.

    This is very weird, I am spent already a week on this.

    Thanks for your help.

    Sharon

    Thursday, December 5, 2019 6:25 PM
  • Firstly, except in the special case of event handlers, whenever you use async you should return Task or Task<T>. This allows the caller to wait for the results. Here's how I'd write your code.

    public async Task Get_iSeeLoc_Locations()
    {
       .....
       Stopwatch S1 = new Stopwatch();
       S1.Start();
    
       var task = await Task.Run(() => Get_iSeeLoc_Real_Locations());
    
       //Continues on calling thread once task completes
       Print_Time();
       S1.Stop();
       Infrastructure.Print_To_Console("Calc Location thread took " + "-"+ S1.ElapsedMilliseconds.ToString() + " MS");
    }

    Then to call it elsewhere, say a UI event handler

    private async void UIHandler ( )
    {
       //Runtime will return from this handler immediately freeing up the UI thread
       await Get_iSeeLoc_Locations();
    
       //The code here will run on UI thread
    }


    Michael Taylor http://www.michaeltaylorp3.net

    Thursday, December 5, 2019 6:36 PM
    Moderator
  • Hi,

    I tried implementing this as recommended and still having the same exact issue.

    One of the method in the Get_iSeeLoc_Real_Locations is a computation that uses a Matlab run time engine. I can see many of those processes in the Threads window.

    Not Flagged 27780 23 Worker Thread Worker Thread MWArray.dll!MathWorks.MATLAB.NET.Utility.MWMCR.EvaluateFunction

    I wonder if this can create an issue?

    Thanks
    Sharon


    Thursday, December 5, 2019 7:40 PM
  • What issue specifically are you seeing? When the method gets called from your UI (I assume) then you should see it make the call to your async Get_ISee… method. As soon as the first await line is hit that method returns back which returns back to the UI and the UI should be responsive again. At some point in the future the underlying task completes and you'll see execution continue at Print_Time(). This should occur on the UI thread so note that it will not happen until the UI thread is available for messages. Once it resumes though it'll run to completion. If you happen to have any code in the UI handler (that called this method) then it would then execute after the await line (again on the UI thread).

    Michael Taylor http://www.michaeltaylorp3.net

    Thursday, December 5, 2019 7:52 PM
    Moderator
  • The issue I see is that when trying to do step-by-step I can get to the await task and when steeping over or steeping in it I am getting back to beginning pf Get_iSeeLoc_Locations method.

    When the caller complete it should restart a timer that will interrupt every n seconds and will invoke the method that calls Get_iSeeLoc_Locations.  I can see that this timer is getting enabled probably from the caller (for some reason it will not stop there when I place a BP) and I am not sure why.

    Your help is very appreciated.

    Thanks

    Sharon

    Thursday, December 5, 2019 8:11 PM
  • Try an approach like this:

    Task.Run( ( ) =>

       {

          Stopwatch S1 = new Stopwatch();

          S1.Start();

          Get_iSeeLoc_Real_Locations();

          Print_Time();

          S1.Stop();

          Infrastructure.Print_To_Console("Calc Location thread took "+ S1.ElapsedMilliseconds + " MS");

       } );

    If required, use Invoke or BeginInvoke for calling Print_Time and Print_To_Console.



    • Edited by Viorel_MVP Thursday, December 5, 2019 8:21 PM
    Thursday, December 5, 2019 8:20 PM
  • The step logic, if I understand you correctly, is behaving properly. An await effectively returns from the function so when you step on an await like control returns to the caller. You will then step to the next line of code in the caller. If that happens to be an await then it'll return to its caller, etc. If you need to step to code after the await then set a breakpoint on the next line. When the original task eventually completes then that code executes (it is async after all) and your breakpoint will get hit.

    "When the caller complete it should restart a timer that will interrupt every n seconds and will invoke the method that calls Get_iSeeLoc_Locations. "

    If I understand correctly you want a timer to call this method periodically. In that case your "UI handler" that I've been referring to is actually a timer event handler then I guess. I assume this is probably a Winforms Timer object then? If so then unfortunately this timer is going to fire at fixed intervals. If you don't need to do any UI work then consider using a different timer instead.

    If you do need to do UI work (and hence the method called on the UI thread) then you'll have to stop the timer each time it is called, do your async work and then start it again. Here's the high level code for the root handler that reacts to the Tick event of the timer.

    private async void OnTimerTick ( object sender, EventArgs e )
    {
       var timer = sender as Timer;
    
       //Stop the timer so it won't overlap, or make this method reentrant - whichever you need
       timer.Stop();
    
       //Do your work
       await Get_iSeeLoc_Locations();
    
       //Start the timer again after the async work has completed
       timer.Start();
    }


    Michael Taylor http://www.michaeltaylorp3.net

    Thursday, December 5, 2019 8:22 PM
    Moderator
  • Hi,

    I am getting the exactly same issue.

    Is it possible that the issue shows up since the caller is not the UI, it is called by a method that is triggered by a timer under the UI.

    See below.

    public void timerSoldiersLocationUpdate_Tick(object sender, EventArgs e) { timerSoldiersLocationUpdate.Stop(); . . . Get_iSeeLoc_Locations(); .//(Shouldn't get here till the computation is finished)

    . . timerSoldiersLocationUpdate.Start(); }


    Thanks

    Sharon

    • Marked as answer by SZohar Thursday, December 5, 2019 11:46 PM
    Thursday, December 5, 2019 9:13 PM
  • You got it....

    I ended up using the UI timer and inserting this into the handler.

    var task = await Task.Run(() => Get_iSeeLoc_Locations());

    I greatly appreciate your time and the effort to help.

    Thanks

    Sharon

    Thursday, December 5, 2019 11:45 PM