Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Issue: AsyncOperationBase<TObject>.Task Can't Finish

Discussion in 'Addressables' started by AllenPocketGamer, May 6, 2019.

  1. AllenPocketGamer

    AllenPocketGamer

    Joined:
    Jun 27, 2015
    Posts:
    1
    This was tested with addressable 0.7.4 and unity 2019.1.0f2.

    The bug show in the following comment.

    Code (CSharp):
    1.      
    2.         internal System.Threading.Tasks.Task<TObject> Task
    3.         {
    4.             get
    5.             {
    6.                 return System.Threading.Tasks.Task.Factory.StartNew(o =>
    7.                 {
    8.                     // Sometimes the following code is called after the function
    9.                     // InvokeCompletionEvent() call.
    10.                     // So the task that returned become unuseful.
    11.                     var asyncOperation = o as AsyncOperationBase<TObject>;
    12.                     // m_waitHandle only initialize here.
    13.                     asyncOperation.WaitHandle.WaitOne();
    14.                     return asyncOperation.Result;
    15.                 }, this);
    16.             }
    17.         }
    18.  
    19. ..................................................................................................................................
    20.  
    21.         internal void InvokeCompletionEvent()
    22.         {
    23.             if (m_CompletedAction != null)
    24.             {
    25.                 m_CompletedAction.Invoke(new AsyncOperationHandle(this));
    26.                 m_CompletedAction.Clear();
    27.             }
    28.  
    29.             if (m_CompletedActionT != null)
    30.             {
    31.                 m_CompletedActionT.Invoke(new AsyncOperationHandle<TObject>(this));
    32.                 m_CompletedActionT.Clear();
    33.             }
    34.             if (m_waitHandle != null)
    35.                 m_waitHandle.Set();
    36.  
    37.             m_InDeferredCallbackQueue = false;
    38.         }
    And this is my fix
    Code (CSharp):
    1.        
    2.         internal System.Threading.Tasks.Task<TObject> Task
    3.         {
    4.             get
    5.             {
    6.                 var bugFix = WaitHandle;
    7.                 return System.Threading.Tasks.Task.Factory.StartNew(o =>
    8.                 {
    9.                     var asyncOperation = o as AsyncOperationBase<TObject>;
    10.                     // asyncOperation.WaitHandle.WaitOne();
    11.                     bugFix.WaitOne();
    12.                     return asyncOperation.Result;
    13.                 }, this);
    14.             }
    15.         }
     
    Last edited: May 6, 2019
    Twyker_gp and Favo-Yang like this.
  2. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    558
    +1

    also, spawning a new thread only for waiting on the wait handle is bad.
    a
    TaskCompletionSource<TObject>
    should be used here (or better yet, make the async operation itself awaitable)
     
    Twyker_gp likes this.
  3. unity_bill

    unity_bill

    Unity Technologies

    Joined:
    Apr 11, 2017
    Posts:
    1,053
    Thanks for the feedback and the clear solution.
     
    MNNoxMortem likes this.
  4. Coffein

    Coffein

    Joined:
    Jan 22, 2016
    Posts:
    19
    This issue is still present in 0.8.6-preview and has caused us a lot of headache. The fix provided works.
     
    Twyker_gp likes this.
  5. Pixelnest

    Pixelnest

    Joined:
    Oct 25, 2013
    Posts:
    27
    Hello, same here I was running into this major issue and the fix works, but it's still just a workaround.
    What's the ETA for a release included a proper fix?
    Thanks.

    Damien
     
    RDeluxe likes this.
  6. unity_bill

    unity_bill

    Unity Technologies

    Joined:
    Apr 11, 2017
    Posts:
    1,053
    should be in the next release.
     
    MNNoxMortem likes this.
  7. haruto-otake

    haruto-otake

    Joined:
    Aug 27, 2014
    Posts:
    2
    when await Task after AsyncOperation is completed, can not finish handle.
    this issue is preset in 1.1.4-preview.

    this is my fix.

    implementation of custom Awaiter made the Task property unnecessary

    Code (CSharp):
    1.  
    2.  
    3. // Usage:    
    4. // try {
    5. //   Sprite result = await rm.ProvideResource<Sprite>(location);
    6. // } catch (Exception e) {
    7. //    Debug.LogException(e);
    8. // }
    9.  
    10. public struct AsyncOperationHandleAwaiter<TObject> : ICriticalNotifyCompletion
    11.     {
    12.         private AsyncOperationHandle<TObject> handle;
    13.         private Action continuation;
    14.  
    15.         public AsyncOperationHandleAwaiter(AsyncOperationHandle<TObject> handle) : this()
    16.         {
    17.             this.handle = handle;
    18.         }
    19.  
    20.         public bool IsCompleted {
    21.             get { return handle.IsDone; }
    22.         }
    23.  
    24.         public void OnCompleted(Action continuation)
    25.         {
    26.             UnsafeOnCompleted(continuation);
    27.         }
    28.  
    29.         public void UnsafeOnCompleted(Action continuation)
    30.         {
    31.             if (this.continuation != null)
    32.             {
    33.                 throw new InvalidOperationException("continuation is already registered.");
    34.             }
    35.  
    36.             if (IsCompleted)
    37.             {
    38.                 continuation();
    39.             }
    40.             else
    41.             {
    42.                 this.continuation = continuation;
    43.                 handle.Completed += OnHandleOnCompleted;
    44.             }
    45.         }
    46.  
    47.         void OnHandleOnCompleted(AsyncOperationHandle<TObject> _)
    48.         {
    49.             if (continuation != null)
    50.             {
    51.                 continuation();
    52.                 continuation = null;
    53.             }
    54.         }
    55.  
    56.         public TObject GetResult()
    57.         {
    58.             if (handle.Status == AsyncOperationStatus.Succeeded)
    59.             {
    60.                 return handle.Result;
    61.             }
    62.             else
    63.             {
    64.                 throw handle.OperationException;
    65.             }
    66.         }
    67.     }
    68.  
    69.     public static class AsyncOperationHandleExtensions
    70.     {
    71.         public static AsyncOperationHandleAwaiter<TObject> GetAwaiter<TObject>(this AsyncOperationHandle<TObject> handle)
    72.         {
    73.             return new AsyncOperationHandleAwaiter<TObject>(handle);
    74.         }
    75.     }
    76.  
     
    Twyker_gp likes this.