WaitWhileでcancelImmediatelyをtrueにすると、NullReferenceExceptionを発生させる
teck124 opened this issue · 3 comments
teck124 commented
Unity: 2022.3.47f1
UniTask Version: 2.5.5
新しく作成したプロジェクトに以下のComponent WaitWhileTest
をAttachして実行すると、以下のエラーが発生します。
なお、cancelImmediatelyをfalseにすると発生しません。
NullReferenceException: Object reference not set to an instance of an object
Cysharp.Threading.Tasks.UniTask+WaitWhilePromise.MoveNext () (at ./Library/PackageCache/com.cysharp.unitask@f7b3c2fbe1/Runtime/UniTask.WaitUntil.cs:254)
--- End of stack trace from previous location where exception was thrown ---
Cysharp.Threading.Tasks.UniTask+WaitWhilePromise.GetResult (System.Int16 token) (at ./Library/PackageCache/com.cysharp.unitask@f7b3c2fbe1/Runtime/UniTask.WaitUntil.cs:218)
TaskObj.Test (System.Threading.CancellationToken token) (at Assets/Scripts/WaitWhileTest.cs:69)
Cysharp.Threading.Tasks.UniTask+ExceptionResultSource.GetResult (System.Int16 token) (at ./Library/PackageCache/com.cysharp.unitask@f7b3c2fbe1/Runtime/UniTask.Factory.cs:238)
Cysharp.Threading.Tasks.UniTaskExtensions.Forget (Cysharp.Threading.Tasks.UniTask task) (at ./Library/PackageCache/com.cysharp.unitask@f7b3c2fbe1/Runtime/UniTaskExtensions.cs:557)
UnityEngine.Debug:LogException(Exception)
Cysharp.Threading.Tasks.UniTaskScheduler:PublishUnobservedTaskException(Exception) (at ./Library/PackageCache/com.cysharp.unitask@f7b3c2fbe1/Runtime/UniTaskScheduler.cs:90)
Cysharp.Threading.Tasks.UniTaskExtensions:Forget(UniTask) (at ./Library/PackageCache/com.cysharp.unitask@f7b3c2fbe1/Runtime/UniTaskExtensions.cs:561)
WaitWhileTest:Update() (at Assets/Scripts/WaitWhileTest.cs:45)
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using UnityEngine;
public class WaitWhileTest : MonoBehaviour
{
private const float c_CallInterval = 0.3f;
private const float c_CancelInterval = 0.5f;
private float m_JustBeforeCancelTime;
private float m_JustBeforeCallTime;
private TaskObj m_TestObj;
private CancellationTokenSource m_TokenSource;
private void ResetTokenSource()
{
m_TokenSource?.Cancel();
m_TokenSource?.Dispose();
m_TokenSource = new CancellationTokenSource();
m_TestObj = new TaskObj();
}
// Start is called before the first frame update
void Start()
{
m_JustBeforeCallTime = m_JustBeforeCancelTime = Time.unscaledTime;
ResetTokenSource();
}
// Update is called once per frame
void Update()
{
if (Time.unscaledTime - m_JustBeforeCancelTime > c_CancelInterval)
{
m_JustBeforeCancelTime = Time.unscaledTime;
ResetTokenSource();
}
if (Time.unscaledTime - m_JustBeforeCallTime > c_CallInterval)
{
m_JustBeforeCallTime = Time.unscaledTime;
m_TestObj.Test(m_TokenSource.Token).Forget();
}
}
void OnDestory()
{
m_TokenSource?.Cancel();
m_TokenSource?.Dispose();
}
}
public class TaskObj
{
private CancellationTokenSource m_CancelTokenSource;
private const float c_FinishElapsedTime = 0.1f;
private float m_StartTime;
public async UniTask Test(CancellationToken token)
{
try
{
CancelAndDisposeTokenSource();
m_CancelTokenSource = CancellationTokenSource.CreateLinkedTokenSource(token);
m_StartTime = Time.unscaledTime;
await UniTask.WaitWhile(IsContinued, cancellationToken:m_CancelTokenSource.Token, cancelImmediately: true);
Debug.Log("Task Finished");
}
catch (OperationCanceledException)
{
Debug.LogWarning("Task Canceled");
}
finally
{
// CancelAndDisposeTokenSource();
}
}
private void CancelAndDisposeTokenSource()
{
m_CancelTokenSource?.Cancel();
m_CancelTokenSource?.Dispose();
m_CancelTokenSource = null;
}
private bool IsContinued()
{
return Time.unscaledTime - m_StartTime > c_FinishElapsedTime;
}
}
teck124 commented
余分な処理があったので、削除しました。以下のコードでも再現します。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using UnityEngine;
public class WaitWhileTest : MonoBehaviour
{
private const float c_CallInterval = 0.3f;
private float m_JustBeforeCallTime;
private TaskObj m_TestObj;
// Start is called before the first frame update
void Start()
{
m_JustBeforeCallTime = Time.unscaledTime;
m_TestObj = new TaskObj();
}
// Update is called once per frame
void Update()
{
if (Time.unscaledTime - m_JustBeforeCallTime > c_CallInterval)
{
m_JustBeforeCallTime = Time.unscaledTime;
m_TestObj.Test(CancellationToken.None).Forget();
}
}
}
public class TaskObj
{
private CancellationTokenSource m_CancelTokenSource;
private const float c_FinishElapsedTime = 0.1f;
private float m_StartTime;
public async UniTask Test(CancellationToken token)
{
try
{
CancelAndDisposeTokenSource();
m_CancelTokenSource = CancellationTokenSource.CreateLinkedTokenSource(token);
m_StartTime = Time.unscaledTime;
await UniTask.WaitWhile(IsContinued, cancellationToken:m_CancelTokenSource.Token, cancelImmediately: true);
Debug.Log("Task Finished");
}
catch (OperationCanceledException)
{
Debug.LogWarning("Task Canceled");
}
finally
{
CancelAndDisposeTokenSource();
}
}
private void CancelAndDisposeTokenSource()
{
m_CancelTokenSource?.Cancel();
m_CancelTokenSource?.Dispose();
m_CancelTokenSource = null;
}
private bool IsContinued()
{
return Time.unscaledTime - m_StartTime > c_FinishElapsedTime;
}
}
neuecc commented
ありがとうございます!
バグ確認できました&原因特定しました!
今日中に修正版をリリースしますのでお待ちくださいー。
neuecc commented
fixed at 2.5.6.