锁定列表会产生死锁

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

我正在开发使用多线程的C#WPF游戏,但遇到一个错误,当我在操场上添加新实体时,该游戏会突然停止。

我有2个任务运行每个刻度,使游戏正常运行。第一个是执行所有calculations并运行模拟的过程。第二个用于在每个刻度中更新renderer

此代码在游戏开始时运行:

Task.Run(() =>
{
    while (state != GameLevelState.Ended)
    {
        Thread.Sleep(1000 / 60);
        if (state == GameLevelState.Paused)
            continue;
        Task.Run(RunSimulation);
        Task.Run(UpdateRenderer);
    }
});

问题开始于实体列表的存储方式,因为我需要通过两个Task对其进行访问,并且还需要在单击按钮时创建一个新的实体。当UI线程要检查,如果实体列表中已经存在另一个相同类型的实体,则会出现死锁。

这里是获取实体的代码:

public List<GameEntity> GetGameEntities(Func<GameEntity, bool> predicate = null)
{
    if (predicate == null)
        predicate = (GameEntity e) => true;

    List<GameEntity> selected = new List<GameEntity>();

    // this is where the execution stops
    lock (Entities)
    {
        foreach (var entityList in Entities)
            selected.AddRange(entityList.Value.Where(predicate));
        return selected;
    }
}

因此,当我尝试在添加实体时获取相同类型的实体时,执行将在锁上停止。我的理论是UI线程找不到空缺,因为其他2个线程/任务不断锁定Entities List。 (它们仅在他们遍历列表时锁定列表)

(我还应该指出,如果不理会这两个任务/线程,它们将永远永远完美地运行。仅当尝试从UI线程创建/添加实体时,它才会停止)

以下是任务执行的相关代码:

private void RunSimulation()

/* ... */
lock (Entities)
{
    foreach (var entityList in Entities.ToArray())
        foreach (GameEntity entity in entityList.Value.ToArray())
            if (!entity.Tick())
            {
                entityList.Value.Remove(entity);
                Application.Current.Dispatcher.Invoke(() => renderer.RemoveEntity(entity));
            }
}
/* ... */

private void UpdateRenderer()

/* ... */
lock (Entities)
{
    foreach (var entityList in Entities)
        foreach (GameEntity entity in entityList.Value.ToArray())
            Application.Current.Dispatcher.Invoke(() => renderer.DrawEntity(entity));
}
/* ... */

我的问题是:如何解决此问题?

我应该复制列表并进行遍历,以便仅在复制时锁定列表吗?还是应该将entity-adding-process委派给执行所有计算的线程?

任何帮助,我们将不胜感激!

c# wpf multithreading list iteration
1个回答
0
投票

不确定这是否可以解决您的问题,但肯定会有助于控制您产生的任务。在完成当前正在运行的任务之前,不会启动新的循环。它使用awaitawait代替Task.Delay

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