通过OpenTK未呈现的其他线程添加到Dictionary的对象

时间:2018-12-14 22:19:41

标签: c# multithreading opengl opentk

我目前正在开发一个《我的世界》副本,并且我目前正在尝试实现从未使用过的多线程(我已经阅读了Microsoft的一些文档,仅此而已)来生成块而不会使游戏挂起一秒钟。

我的World类存储一个Chunk的字典(System.Collections.Generic),每个字典都存储一个3d的块ID数组。在我的Update方法中,我将要生成的新块添加到队列中(按预期工作),并且我有一个不同的线程应该在队列中工作并逐个生成块:

(在World类中:)

Dictionary<Vector2, Chunk> chunks = new Dictionary<Vector2, Chunk>();
Queue<Vector2> chunksToCreate = new Queue<Vector2>();

public World(Chunk.ChunkGen generator, int program, int seed) {
    generatorFunc = generator;
    Program = program;
    Seed = seed;
    chunksCreator = new Thread(CreateChunks);
    chunksCreator.Start();
}

private void CreateChunks() {
    while (true) {
        if (chunksToCreate.Count == 0)
            continue;
        Vector2 vec = chunksToCreate.First();
        chunks[vec] = generatorFunc(this, (int)vec.X, (int)vec.Y);
        chunksToCreate.TryDequeue(out Vector2 outVec);
    }
}

我的问题是,当我仅通过调用generatorFunc(delegate)创建块时,会将它们添加到字典中,并按预期由opentk呈现,但是当我使用另一个线程创建时,它们也会被添加到字典中,并且在VS Debugger中,对象内部的所有内容看起来都是正确的,但它们根本没有呈现。

我已经尝试使用ConcurrentQueueConcurrentDictionary,但没有任何更改。

如果有人能为我提供帮助,我将非常感激,因为我对所有这些多线程技术完全陌生,而且所有文章和书籍似乎都让人觉得不知所措。

1 个答案:

答案 0 :(得分:2)

UI不喜欢在其他线程中创建的图形对象。例如。如果您的块包含画笔,那么如果它们是在工作线程中创建的,则它们可能无法在UI线程中工作。

在您的情况下,无论您使用普通集合还是线程安全集合都没有区别,因为您仅创建了一个线程。要体验速度提升,必须创建并运行多个线程。在这种情况下,使用线程安全的集合将至关重要,而CreateChunks方法必须看起来像

private void CreateChunks() {
    while (chunksToCreate.TryDequeue(out Vector2 vec)) {
        chunks.TryAdd(vec, generatorFunc(this, (int)vec.X, (int)vec.Y));
    }
}

但是使用Task Parallel Library (TPL)可以避免创建正确数量的线程并自己管理它们。

Parallel.ForEach(chunksToCreate, vec =>
    chunks.TryAdd(vec, generatorFunc(this, (int)vec.X, (int)vec.Y))
);

请注意,源chunksToCreate不必是线程安全的,因为Parallel.ForEach会在启动线程之前将它们分配给线程。但是,必须使用字典chunks,因为它将由多个线程并行访问。


ConcurrentDictionary<Vector2, Chunk> chunks = new ConcurrentDictionary<Vector2, Chunk>();
List<Vector2> chunksToCreate = new List<Vector2>();

public World(Chunk.ChunkGen generator, int program, int seed) {
    Program = program;
    Seed = seed;
    Parallel.ForEach(chunksToCreate, vec =>
        chunks.TryAdd(vec, generator(this, (int)vec.X, (int)vec.Y))
    );
}