Search Unity

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:
    485
    +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:
    954
    Thanks for the feedback and the clear solution.
     
    MNNoxMortem likes this.
  4. Coffein

    Coffein

    Joined:
    Jan 22, 2016
    Posts:
    17
    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:
    23
    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:
    954
    should be in the next release.
     
    MNNoxMortem likes this.
  7. haruto-otake

    haruto-otake

    Joined:
    Aug 27, 2014
    Posts:
    1
    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.