LoginSignup
2
3

More than 5 years have passed since last update.

Unity Task実行 Taskキャンセル async await メモ

Last updated at Posted at 2018-04-24

●参考URL
 http://mslgt.hatenablog.com/entry/2017/10/08/091841
 https://qiita.com/toRisouP/items/a2c1bb1b0c4f73366bc6

■SynchronizationContext

SynchronizationContext は、スレッドごとにインスタンスを持っているとの事

SynchronizationContext.Currentすると現在のスレッドを取得できる

■CancellationTokenSource

別スレッド動作しているタスクの処理をキャンセルするために使用する。

■メインスレッドに処理を返す

Unity関係のクラスを操作しようと思うとメインスレッド以外では使用できないので。

下部にあるコードのように、UnityのメインスレッドでSynchronizationContext.Currentを使ってカレントスレッドを保持しておき

別スレッドからはPostでメインスレッド処理。

■Taskの処理を外からキャンセル。

CancellationTokenSource tokenSource = new CancellationTokenSource(); を定義

tokenSource.Cancel() を外側の処理で実行し、
Task内でtokenSource.Token.IsCancellationRequested にて判定する

■テストコード

using UnityEngine;
using UnityEngine.UI;
using System.Threading;
using System.Threading.Tasks;

public class TaskTest : MonoBehaviour {

    // MainThreadのコンテキストを取得.
    SynchronizationContext context = null;
    CancellationTokenSource tokenSource = new CancellationTokenSource();

    [SerializeField]
    private Text TestLabel;

    public void OnClickAwaitButton()
    {
        Debug.Log("OnClickAwaitButton() S");

        // MainThreadのコンテキストを取得.
        context = SynchronizationContext.Current;
        Work();

        Debug.Log("OnClickAwaitButton() E");
    }

    /// <summary>
    /// async・awaitを使ってTaskを処理する
    /// </summary>
    /// <returns></returns>
    async Task Work()
    {
        Debug.Log("実行開始");

        await Task.Run(() =>
        {
            MethodC();
            MethodD();
            EndMethod();
        });

        Debug.Log("実行終了");
    }

    void MethodC()
    {

        for (int i = 0; i < 10000; i++)
        {
            Debug.Log("MethodC=" + i.ToString());
            // Taskのキャンセルチェック。
            if (tokenSource.Token.IsCancellationRequested)
            {
                Debug.Log("MethodC Cancel");
                return;
            }
            // メインスレッド側の処理を行う
            context.Post((state) =>
            {
                TestLabel.text = i.ToString();
            }
            , null);
        }
    }

    void MethodD()
    {
        for (int j = 10000; j < 20000; j++)
        {
            Debug.Log("MethodD=" + j.ToString());
            // Taskのキャンセルチェック。
            if (tokenSource.Token.IsCancellationRequested)
            {
                Debug.Log("MethodD Cancel");
                return;
            }
            // メインスレッド側の処理を行う
            context.Post((state) =>
            {
                TestLabel.text = j.ToString();
            }
            , null);
        }
    }

    void EndMethod()
    {
        Debug.Log("EndMethod");

        // Taskのキャンセルチェック。
        if (tokenSource.Token.IsCancellationRequested)
        {
            Debug.Log("EndMethod() Cancel");
            return;
        }

        // メインスレッド側の処理を行う
        context.Post((state) =>
        {
            TestLabel.text = "終了!";
        }
        , null);

    }

    /// <summary>
    /// キャンセルボタン
    /// </summary>
    public void OnClickCancelButton()
    {
        Debug.Log("OnClickCancelButton() S");

        // トークンを使って、Taskをキャンセルする。
        tokenSource.Cancel();

        Debug.Log("OnClickCancelButton() E");
    }
}

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3