繁体   English   中英

Unity3d和线程

[英]Unity3d and Threading

我想在我的应用程序中做一些耗时但对实际游戏没有影响的东西。 因此,我试图使用一个线程分别运行这些东西。 以下是我创建线程的方法:

Thread thread = new Thread(() => WriteCheckpointTextFile (myFileName, checkpoint));
thread.Start();

这是我在WriteCheckpointTextFile中运行的代码:

void WriteCheckpointTextFile (string fileName, Checkpoint checkpoint)
{
            string checkpointToText = "";
            checkpointToText += CheckpointDataNames.nextMarker + Environment.NewLine;
            checkpointToText += checkpoint.nextMarker + Environment.NewLine;
            checkpointToText += "%" + Environment.NewLine;

            checkpointToText += CheckpointDataNames.difficulty + Environment.NewLine;
            checkpointToText += checkpoint.difficulty.ToString () + Environment.NewLine;
            checkpointToText += "%" + Environment.NewLine;

            checkpointToText += CheckpointDataNames.musicObject + Environment.NewLine;
            checkpointToText += checkpoint.musicObject + Environment.NewLine;
            checkpointToText += "%" + Environment.NewLine;

            checkpointToText += CheckpointDataNames.gameTimePassed + Environment.NewLine;
            checkpointToText += checkpoint.gameTimePassed.ToString () + Environment.NewLine;
            checkpointToText += "%" + Environment.NewLine;


            checkpointToText += CheckpointDataNames.storedStats + Environment.NewLine;
            checkpointToText += EndRaceDataString (checkpoint.storedStats);
            checkpointToText += "%" + Environment.NewLine;

            checkpointToText += CheckpointDataNames.pursuers + Environment.NewLine;
            foreach (PursuerData p in checkpoint.pursuers) {
                    checkpointToText += p.pursuerName + "," + p.pursuerNextMarker + "," + p.pursuerPosition.x.ToString () + "," + p.pursuerPosition.y.ToString () + "," + p.pursuerPosition.z.ToString () + Environment.NewLine;

            }
            checkpointToText += "%" + Environment.NewLine;
            #if !UNITY_WEBPLAYER

            System.IO.File.WriteAllText (fileName, checkpointToText);

            #endif
            Debug.Log("Finished writing text to file");
}

现在出于某种原因,上次调试并不总是打印出来,并且我的文件并不总是被写入。 可能是什么导致了这个?

问题是你的集合checkpoint.storedStats正在从另一个线程(可能你是主线程)被修改,而你在后台线程中迭代它。 这会抛出InvalidOperationException 因为您的代码是在后台线程上执行的,所以Unity播放器/引擎会以静默方式抛出,未处理并忽略该异常。

不幸的是,这意味着您必须同步或限制对checkpoint.storedStats集合的访问和更改,以便只有1个线程可以对其进行修改,并且在执行此操作时,其他线程不得对其进行迭代。

很难对您实施的最佳或最简单的方法发表评论,因为我不知道您在整个应用程序中如何使用storedStats集合。 一种可能的,相当典型的解决方案是使用lock语句包装所有位置访问集合。 这将确保在任何给定时间只有1个线程进入锁定块。 然后,当访问storedStats进行读取 (而不是写入 )时,您可以在storedStats的脚本上提供一个方法来lock集合,复制它并返回该副本。 由于它是一个副本,您可以安全地迭代它:

public class Checkpoint : MonoBehaviour
{
    //used for locking
    private readonly object ThreadLocker = new Object();

    private List<Stat> storedStats = new List<Stat>();

    public List<State> GetStoredStatsCopy()
    {
        lock(ThreadLocker)
        {
            //makes a copy/snapshot of the list
            return new List<Stat>(storedStats);
        }
    }

    //sample code that changes storedStats
    public void AddStat(Stat newStat)
    {
        lock(ThreadLocker)
        {
            storedStats.Add(newStat);
        }
    }
}

请注意, Checkpoint脚本现在使storedStats 私有 我还添加了一些修改写入底层storedStats示例方法。 因此,对该storedStats 所有访问storedStats受到控制,并且线程也是同步的。 这样你的后台线程就不能在storedStats集合上进行迭代(因为它有一个副本,并且副本的创建是受控/线程安全的),并且对集合的任何写入都不能与另一个线程同时发生。访问它。

编辑:通过上述API更改,您的调用代码可能如下所示:

checkpointToText += EndRaceDataString (checkpoint.GetStoredStatsCopy());

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM