同时运行多个线程,返回它们的结果并使用它们来做某事

问题描述 投票:0回答:1

我一直在尝试为我在 Godot 中制作的游戏编写一个块加载系统。为此,我想使用线程一次加载多个块。

int threadsToUtilise = 7;

Thread[] threads; // array to store threads

ArrayMesh[] threadResults; // array to save meshes returned by WorldLoader.GetChunk();

Vector3I[] chunkIDsLoading; // array to save position (Vector3I) of the chunk thread[i] is loading; serves to later position the mesh at the right position

// the arrays are initialised with a size of threadsToUtilise (7)

List<Vector3I> chunksToLoad = new(); // List to store positions of all chunks that still need to be loaded in

public override void _Process(double delta) // method runs every frame
{
    for (var i = 0; i < threadsToUtilize; i++)
    {
        if (threads[i] == null){
            if (chunksToLoad.Count == 0) break;
            threads[i] = new Thread(() => { threadResults[i] = WorldLoader.GetChunk(chunksToLoad[0], false); });
            threads[i].Start();
            chunkIDsLoading[i] = chunksToLoad[0];
            chunksToLoad.RemoveAt(0);
        }
        else if (!threads[i].IsAlive) {
            if (threadResults[i] != null) {
            // implement some stuff
            }
            threads[i] = null;
            threadResults[i] = null;
            chunkIDsLoading[i] = Vector3I.Zero;
        }
    }
}

通常我想加载一个块,并在创建网格后立即实现它。它或多或少有效,但有两个主要问题:

  1. 有时,非常随机地出现错误:索引超出了数组的范围。 这发生在创建线程并分配 threadResults[i] = WorldLoader.GetChunk... 的行中。但情况不应该是这样,因为数组是用threadsToUtilise的大小创建的,并且循环也依赖于它。
  2. 有时块放置正确,有时它们偏离了应有的位置(大约太早/太晚 1 或 2 个块位置)。创建网格的方法效果很好,我确实测试了该方法。
c# multithreading
1个回答
0
投票

这看起来像是一个“捕获”问题;尝试:

var idx = i;
var chunk = chunksToLoad[0];
threads[i] = new Thread(() => { threadResults[idx] = WorldLoader.GetChunk(chunk, false); });

它创建我们在 lambda 中“捕获”的值的快照。

© www.soinside.com 2019 - 2024. All rights reserved.