Как в дочернем потоке приостановить выполнение кода , вы полнить метод в основном потоке , а потом продолжить выполнение дочернего потока?

208
03 января 2022, 05:40

Постоянно сталкиваюсь с ошибкой :

UnityException: GetAssetPath can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.

Мне надо выполнить метод AssetDatabase.GetAssetPath(GamObjArrayTexture[i]);, на котором обрывается всё выполнение кода, так как это не основной поток. Эти советы тоже не помогают :

List<string> listStringUrlTexture = new List<string>();
string path;
Thread thread = new Thread(() => { AssetDatabase.GetAssetPath(GamObjArrayTexture[i]); });
thread.Start();
listStringUrlTexture.Add(path);

Так как у меня всё это выполняется не в основном потоке.

Как мне переписать код с потоками, чтоб когда выполнялся метод (который возвращает значение) не выкидывал ошибок?

Мой код :

private Worker _worker;
public static bool pressedbool = false;
private Thread _thread;
private UnityEngine.Object _locker;
public static int _progress;
com.youvisio.BackgroundWorker _backgroundWorker;
public string InfoStr;
void DrawFooter()
{
    GUILayout.BeginArea(FooterSection);
    GUILayout.BeginVertical();
    if (!pressedbool)
    {
        GUILayout.Label("Выберите json");
        GUILayout.BeginHorizontal();
        stringTextFieldURLjsonfile = GUILayout.TextField(stringTextFieldURLjsonfile);
        if (GUILayout.Button("Обзор...", GUILayout.Width(100)))
        {
            stringTextFieldURLjsonfile = EditorUtility.OpenFilePanel("Выбрать json", "", "json");
        }
        GUILayout.EndHorizontal();
        if (GUILayout.Button("Старт"))
        {
            if (TerrainList != null && TerrainList.Count() > 0)
            {
                pressedbool = true;
                _worker = new Worker();
                _worker.ProcessChanged += worker_ProcessChanged;
                _worker.WorkCompleted += worker_WorkCompleted;
                _worker.WorkLog += worker_Log;
                _worker.myList = myList;
                _worker.count_list_index = count_list_index;
                _worker.GamObjArrayTexture = GamObjArrayTexture;
                _worker.TerrainList = TerrainList;
                _worker.brushsize = brushsize;
                Worker._cancelled = false;
                // _thread = new Thread(() => _worker.ProcessJSONPlaceONmapTextures("", null));
                // _thread.IsBackground = true;
                _thread = new Thread(_worker.Work);
                // if (count_list_index >= 0)
                // {
                //     if (myList[count_list_index].geometry_type == 0)
                //     {
                //         ProcessJSONPlaceONmapTextures();
                //     }
                //     else if (myList[count_list_index].geometry_type == 1)
                //     {
                //         // ProcessJSONPlaceONmap();
                //     }
                // }
                _locker = new UnityEngine.Object();
                _progress = 0;
                _thread.Start();
            }
            else
            {
                Debug.Log("Terrain List пуст. Назначьте террейны.");
            }
        }
    }
    else
    {
        if (GUILayout.Button("Стоп"))
        {
            pressedbool = false;
            Worker.Cancel();
        }
        if (_backgroundWorker != null) _backgroundWorker.Update();
        EditorGUI.ProgressBar(new Rect(3, 45, FooterSection.width - 6, 20), _progress / 100.0f, "progress: " + _progress + "%");
    }
    GUILayout.EndVertical();
    GUILayout.EndArea();
}
// IEnumerator LoadingRoutine()
// {
//     while (_thread.IsAlive)
//     {
//         lock (_locker)
//         {
//             _progress = EditorGUILayout.IntSlider(Rect(3, 3, position.width - 6, 15), "progress:", _progress, 0, 100);
//         }
//         yield return null;
//     }
// }
public static void worker_WorkCompleted(bool cancelled)
{
    Action action = () =>
    {
        string messeg = cancelled ? "Процесс отменён" : "Процесс завершён!";
        Debug.Log("messeg=" + messeg);
        pressedbool = false;
    };
    action();
    // if (InvokeRequired)
    //     Invoke(action);
    // else
    //     action();
}
public static void worker_ProcessChanged(int progress)
{
    Action action = () => { _progress = progress; };
    // if (InvokeRequired)
    //     Invoke(action);
    // else
    //     action();
    action();
}
public static void worker_Log(string str)
{
    Action action = () => { Debug.Log(str); };
    // if (InvokeRequired)
    //     Invoke(action);
    // else
    //     action();
    action();
}
void OnInspectorUpdate()
{
    Repaint();
}

Класс worker(выполняется в дочернем потоке):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;
internal class Worker
{
    public static bool _cancelled = false;
    public List<Terrain> lstTerrain = null;
    public List<string> listStringUrlTexture = null;
    public List<int> idtexture = null;
    public List<mapObject> myList = null;
    public int count_list_index = -3;
    public Texture2D[] GamObjArrayTexture = null;
    public Terrain[] TerrainList = new Terrain[0];
    public float brushsize = 3;
    public static void Cancel()
    {
        _cancelled = true;
    }
    public void Work()
    {
        for (int i = 0; i <= 100; i++)
        {
            if (_cancelled) break;
            // if (a.IsCanceled) return;
            Thread.Sleep(50);
            Debug.Log("обрабатывается...");
            marijnz.EditorCoroutines.PlacementObjects.worker_ProcessChanged(20);
            if (templstTerrain != null)
            {
                lstTerrain = templstTerrain;
            }
            else
            {
                lstTerrain = TerrainList.OfType<Terrain>().ToList();
            }
            if (TerrainList != null && TerrainList.Count() > 0)
            {
                marijnz.EditorCoroutines.PlacementObjects.worker_ProcessChanged(0);
                listStringUrlTexture = getListStringUrlTexture();
                marijnz.EditorCoroutines.PlacementObjects.worker_ProcessChanged(25);
            }
            marijnz.EditorCoroutines.PlacementObjects.worker_ProcessChanged(i);
        }
        marijnz.EditorCoroutines.PlacementObjects.worker_WorkCompleted(_cancelled);
    }
    public event Action<int> ProcessChanged;
    public event Action<bool> WorkCompleted;
    public event Action<string> WorkLog;
}
public static List<string> getListStringUrlTexture()
{
    List<string> listStringUrlTexture = new List<string>();
    // List<Thread> listThreads = new List<Thread>();
    for (int i = 0; i < GamObjArrayTexture.Length; i++)
    {
        if (GamObjArrayTexture[i] != null)
        {
            string path = AssetDatabase.GetAssetPath(GamObjArrayTexture[i]);
            listStringUrlTexture.Add(path);
        }
    }
    foreach (var singlValueList in listStringUrlTexture)
    {
        Debug.Log(singlValueList);
    }
    return (listStringUrlTexture.Count > 0) ? listStringUrlTexture : null;
}

Как отправить в main thread выполнение getListStringUrlTexture() метода?

Answer 1

Ответ я опубликовал тут. В краце класс Dispatcher помогает избежать ошибок типа :

UnityException: GetAssetPath can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
READ ALSO
SESSION не изменяется

SESSION не изменяется

Через fetch в файл сorephp отправляется action, который равен 'login', а так же email и epass

245
Проблема включения Apache в утилите MAMP

Проблема включения Apache в утилите MAMP

Во время нажатия кнопки Start Server загорается зеленый круг на Apache,через 1 секунду уже на MySQL,затем с Apache пропадает зеленый круг и остается только...

194