使用线程数组

时间:2014-01-02 16:54:29

标签: c# multithreading

我是新手,所以对你来说这可能很简单,但我花了几个小时试图解决它。

假设我有一个功能

public double Gain(List<int> lRelevantObsIndex, ushort uRelevantAttribute)

需要一些时间才能完成,但只是一个只读的功能。

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

这是我到目前为止所做的,但它不起作用:

lRelevantObsIndex 是一个只读索引。

lRelevantAttributes 是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;

我知道这是一个简单的多线程问题 - 但由于我是新手,所以仍然需要你的大脑。

3 个答案:

答案 0 :(得分:4)

这个有点棘手:你的for循环在这里使用修改后的值(所谓的access to modified closure

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

在线程启动时,i在lambda中会有所不同,访问错误的项目。修改你的循环如下:

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();
}

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

答案 1 :(得分:2)

我不确定这是不是你的问题,但它是 问题:

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

当lambda引用循环变量时,绑定会被延迟,因此当lambda实际运行时,它会在lambda运行时获取i 的值,而不是lambda创建时的值。要解决这个问题,请在循环中声明一个辅助变量,并在lambda中使用它:

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

答案 2 :(得分:1)

您可以在Task

上执行相同的操作
    [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