You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#多线程调用对象方法并等待全部完成问题求助

多线程调用对象方法时的异常问题解决

问题背景

我有一个对象列表,需要调用每个对象的ComplexTask方法——该方法逻辑复杂、耗时较长。我想通过多线程分别调用每个方法,再等待所有线程执行完毕,但当前实现无法正常运行。

当前实现代码

List<Task> TaskList = new List<Task>();
foreach (ComplexObject co in population)
{
    TaskList.Add(Task.Run(() => co.ComplexTask()));
}
Task.WaitAll(TaskList.ToArray());

异常情况

执行时抛出NullReferenceException(空引用异常),但同步调用ComplexTask方法完全正常,推测是Task的使用方式存在错误。

补充:ComplexTask方法代码

public int ComplexTask()
{
    int maquinaCubierta = 100;
    int maquinasNoCubierta = -100;

    int empleadoHabitual = 50;
    int empleadoNoHabitual = 25;
    int empleadoAVarios = 15;

    int empleadoCambioTurno = -75;

    int ett = -10;

    fitness = 0;

    bool perfecto = true;

    procesarCalendario();

    for (int dia = 0; dia < 5; dia++)
    {
        for (int turno = 0; turno < 3; turno++)
        {
            foreach (String key in asignaciones[dia][turno].Keys)
            {
                if (asignaciones[dia][turno][key] == null)
                {
                    if (puestosSemana[dia][turno][0].Contains(key))
                    {
                        fitness += maquinaCubierta + ett;
                    }
                    else
                    {
                        fitness += maquinasNoCubierta;
                        perfecto = false;
                    }
                }
                else if (asignaciones[dia][turno][key].kPuesto == key)
                {
                    fitness += maquinaCubierta;

                    fitness += asignaciones[dia][turno][key].kPuesto == key ? empleadoHabitual : empleadoNoHabitual;

                    if (asignaciones[dia][turno][key].turno != turno + 1)
                    {
                        fitness += empleadoCambioTurno;
                        perfecto = false;
                    }
                }
            }

            fitness += empleadoAVarios * empleadosSinAsignacion[dia][turno].Count;
        }
    }

    if(perfecto)
    {
        fitness = int.MaxValue;
    }

    return fitness;
}

问题原因及解决方案

核心问题:循环变量捕获陷阱

当前代码存在foreach循环变量捕获的经典问题:异步Task执行时,循环可能已经完成迭代,导致多个Task共享同一个co引用,甚至引用到已失效的对象,最终引发空引用异常或错误调用其他对象的方法。

修复后的代码

在循环内部创建局部变量保存当前迭代的对象,再捕获该局部变量:

List<Task> TaskList = new List<Task>();
foreach (ComplexObject co in population)
{
    // 新增局部变量保存当前迭代的对象实例
    var currentCo = co;
    TaskList.Add(Task.Run(() => currentCo.ComplexTask()));
}
Task.WaitAll(TaskList.ToArray());

额外检查点

  1. 线程安全性验证:确认ComplexTask中访问的asignaciones、puestosSemana、fitness等成员变量是否为对象私有属性,不会被其他线程并发修改。若存在共享资源,需添加锁(如lock语句)保护。
  2. procesarCalendario方法检查:排查该方法是否会修改共享资源,或存在潜在的空引用风险——同步执行正常不代表多线程场景下不会暴露问题。

内容的提问来源于stack exchange,提问作者Ruben Arranz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 10:10:33