C# 使用线程数组

C# 使用线程数组,c#,multithreading,C#,Multithreading,我是线程新手,所以这对你来说可能很简单,但我已经花了几个小时试图弄明白 假设我有一个函数 public double Gain(List<int> lRelevantObsIndex, ushort uRelevantAttribute) 它需要一些时间才能完成,但它是一个只读函数 我有一个ushort[]值数组,我想得到实现增益函数最小值的ushort值 到目前为止,我已经掌握了以下信息,但它不起作用: LRElevationToBSIndex是只读索引 LRelevatAttr

我是线程新手,所以这对你来说可能很简单,但我已经花了几个小时试图弄明白

假设我有一个函数

public double Gain(List<int> lRelevantObsIndex, ushort uRelevantAttribute)
它需要一些时间才能完成,但它是一个只读函数

我有一个ushort[]值数组,我想得到实现增益函数最小值的ushort值

到目前为止,我已经掌握了以下信息,但它不起作用:

LRElevationToBSIndex是只读索引

LRelevatAttributes是ushort值的列表

        //Initialize the threads
        double[] aGains = new double[lRelevantAttributes.Count];
        Thread[] aThreads = new Thread[lRelevantAttributes.Count];
        for (int i = 0; i < lRelevantAttributes.Count; i++)
        {
            aThreads[i] = new Thread(() => aGains[i] = Gain(lRelevantObsIndex, lRelevantAttributes[i]));
            aThreads[i].Start();
        }

        //Join the threads
        for (int i = 0; i < lRelevantAttributes.Count; i++)
            aThreads[i].Join();

        //The easy part - find the minimum once all threads are done
        ushort uResult = 0;
        double dMinGain = UInt16.MaxValue;
        for (int i = 0; i < lRelevantAttributes.Count; i++)
        {
            if (aGains[i] < dMinGain)
            {
                dMinGain = aGains[i];
                uResult = lRelevantAttributes[i];
            }
        }

        return uResult;

我知道这是一个简单的多线程问题,但仍然需要你的大脑,因为我是新手。

这个问题有点棘手:for循环在这里使用了一个修改过的值,即所谓的


这将解决问题,因为lambdas将在循环的每次迭代中捕获临时变量i的当前值。

这一个有点棘手:for循环在这里使用一个修改后的值,即所谓的


这将解决问题,因为lambdas将在循环的每次迭代中捕获临时变量i的当前值。

我不确定这是否是您的问题,但这是一个问题:


我不确定这是否是你的问题,但这是一个问题:

你也可以这样做

你也可以这样做


当你说它不起作用时,你能更具体一点吗?它以什么方式不起作用?行为是什么?@dvnrrs,当然,它会在第一个for循环中抛出一个异常。它正在尝试访问数组[i],而i设置为30。我猜这是因为线程使用不当造成的。好吧,是的,这是下面答案中描述的访问修改的闭包问题的结果。您实际需要的更像是Parallel.ForEachlRelevantAttributes。。。。我怀疑在这里创建单独的线程是否经济,你测量过什么吗?。这当然是很难做到的。当你说它不起作用时,你能更具体一点吗?它以什么方式不起作用?行为是什么?@dvnrrs,当然,它会在第一个for循环中抛出一个异常。它正在尝试访问数组[i],而i设置为30。我猜这是因为线程使用不当造成的。好吧,是的,这是下面答案中描述的访问修改的闭包问题的结果。您实际需要的更像是Parallel.ForEachlRelevantAttributes。。。。我怀疑在这里创建单独的线程是否经济,你测量过什么吗?。这当然是很难做到的。这正是问题所在;我比我想承认的更喜欢这个。记住,伙计们——lambda不是在循环中计算的,它们在任何变量上都是闭合的,并且在您实际调用它们时进行计算;在这种情况下,在一些背景线程集上。这正是问题所在;我比我想承认的更喜欢这个。记住,伙计们——lambda不是在循环中计算的,它们在任何变量上都是闭合的,并且在您实际调用它们时进行计算;在本例中,在一些背景线程集上。
for (int i = 0; i < lRelevantAttributes.Count; i++)
{
    aThreads[i] = new Thread(() => aGains[i] = Gain(lRelevantObsIndex, lRelevantAttributes[i]));
    aThreads[i].Start();
}
for (int ii = 0; ii < lRelevantAttributes.Count; ii++)
{
    var i = ii; // Now i is a temporary inside the loop, so its value will be captured instead
    aThreads[i] = new Thread(() => aGains[i] = Gain(lRelevantObsIndex, lRelevantAttributes[i]));
    aThreads[i].Start();
}
for (int i = 0; i < lRelevantAttributes.Count; i++)
{
    aThreads[i] = new Thread(() => aGains[i] = Gain(lRelevantObsIndex, lRelevantAttributes[i]));
    aThreads[i].Start();
}
for (int i = 0; i < lRelevantAttributes.Count; i++)
{
    int j = i;
    aThreads[i] = new Thread(() => aGains[j] = Gain(lRelevantObsIndex, lRelevantAttributes[j]));
    aThreads[i].Start();
}
    [Fact]
    public void Test()
    {
        List<Task<int>> tasks = Enumerable.Range(0, 5) //- it's equivalent how many threads
                                          .Select(x => Task.Run(() => DoWork(x)))
                                          .ToList();
        int[] result = Task.WhenAll(tasks).Result; //- Join threads

        result.ToList().ForEach(Console.WriteLine);
    }

    private int DoWork(int taskId)
    {
        return taskId;
    }
3
0
1
2
4