Search Unity

Bug Async await freeze after Winform event fires

Discussion in 'Scripting' started by Threeyes, Mar 28, 2023.

  1. Threeyes

    Threeyes

    Joined:
    Jun 19, 2014
    Posts:
    80
    I use winform dll to create contextmenu for my windows app, and subscribe context button's MouseDown event to open a UI Window:
    Code (CSharp):
    1.  
    2. void Init
    3. {
    4.       notifyIcon.MouseDown +=OnNotifyIcon_MouseDown;
    5. }
    6. .
    7. .
    8. void OnNotifyIcon_MouseDown(object sender, MouseEventArgs e)
    9. {
    10.        UIWindow.Open(); //Open UI Window
    11. }
    upload_2023-3-28_23-31-33.png

    but after I click any of the context button and open the UI, all async codes freeze on await Task (but the program not freeze), which all running well before the clicking:
    Code (CSharp):
    1.     async void QeuryPageItems(int pageIndex)
    2.     {
    3.         await Task.Yield();//Freezed here
    4.         ...//Can't be executed
    5.     }
    Did anyone encounter this problem? Thanks!

    Btw, I am using Unity2021.3.5f1
     
    Last edited: Jan 10, 2024
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    My guess is that the app is "awaiting" without telling Unity it can continue rendering frames/etc, which would indeed just result in a freeze. Unity isn't really built with the default C# async/await in mind - the "official" way to do asynchronous code is with coroutines.

    Try using the UniTask library. It's honestly been one of the best recent additions to my own Unity repertoire, and it's easily the best way to do asynchronous code in Unity, and IMO it's only a matter of time before it gets integrated into Unity. With that library your code would become:
    Code (csharp):
    1. async UniTask QueryPageItems(int pageIndex)
    2. {
    3. await UniTask.DelayFrame(1);
    4. // etc
    5. }
    And that much I can confidently say, does not freeze Unity.
     
  3. Threeyes

    Threeyes

    Joined:
    Jun 19, 2014
    Posts:
    80
    Thanks for your reply, I had try UniTask before and it works well, but some of my plugins has using Unity async/await for a long time and it's hard to support extra library, so I wonder if there are any solution for this?
     
  4. AdamLiu

    AdamLiu

    Joined:
    Mar 19, 2014
    Posts:
    71
    Did you manage to solve this at last?
     
  5. bugfinders

    bugfinders

    Joined:
    Jul 5, 2018
    Posts:
    1,726
    if you rock over to 2023.1 the "await Awaitable.yourchoice" works exceptionally well.
     
  6. Threeyes

    Threeyes

    Joined:
    Jun 19, 2014
    Posts:
    80
    Sorry but not luck, Unity 2022.3 still have the same problem, so I have to ditch all winfrom UI. maybe you can try 2023.1 as #5 bugfinders mentioned.
     
  7. Threeyes

    Threeyes

    Joined:
    Jun 19, 2014
    Posts:
    80
    Thanks! I will try it once the 2023.1 (or Unity6) LTS has released!
     
  8. bugfinders

    bugfinders

    Joined:
    Jul 5, 2018
    Posts:
    1,726
    well 2023.1 will not be lts, they never are, i think this year its not even .3 which will be LTS rumour has it its gonna be .4 this year..

    but it is officially released, in fact its moved on to .2 now

    upload_2024-1-9_9-1-12.png
     
    Threeyes likes this.
  9. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,842
    I wonder if Editor-coroutines is a potential solution here?
     
  10. Threeyes

    Threeyes

    Joined:
    Jun 19, 2014
    Posts:
    80
  11. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,842
    Fair, didn't know if this was an editor or runtime tool.

    Though you can of course use coroutines in a build/runtime no problem.
     
  12. Nad_B

    Nad_B

    Joined:
    Aug 1, 2021
    Posts:
    725
    You may have a deadlock, since WinForms and Unity runs on different main threads/dispatchers, so before calling await Task.Yield(), you will need to switch back to Unity's main thread, see this on how to achieve it:

    https://discussions.unity.com/t/how-do-i-invoke-functions-on-the-main-thread/49832/4

    Or if you're using a recent Unity version, this could work:
    Code (CSharp):
    1.  
    2. // Go back to Unity main thread
    3. await Awaitable.MainThreadAsync();
    4.  
    5.  await Task.Yield();
    6.  
    Although, me personally, I'd use (the excellent) UniTask and call it a day.
     
    Threeyes likes this.