多线程时出现意外结果

时间:2017-05-15 12:44:55

标签: c# multithreading loops

我有一个由start和end参数启动的线程调用的函数。在单个主线程上运行时,该函数可以正常工作。但是,当我尝试多线程时,代码会中断。

功能如下:

static void processThread(long startLimit, long endLimit)
    {
        long rangeLimit = startLimit;
        while (startLimit < endLimit) {
            rangeLimit = rangeLimit + 100;
            startLimit++;
            Console.WriteLine("Processed for " + startLimit + ", " + rangeLimit); 
            startLimit = rangeLimit;
        }
    }

我从main调用它为::

int threadCount = 4;
long[] startPoints = new long[threadCount];
long[] endPoints = new long[threadCount];
if ((endLimit / 100) % threadCount == 0)
{
    for (int i = 0; i < threadCount; i++)
    {
        endPoints[i] = endLimit * (i + 1) / threadCount;
    }
    startPoints[0] = 0;
    for (int i = 1; i < threadCount; i++)
    {
        startPoints[i] = endPoints[i - 1];
    }
}
Thread[] threads = new Thread[threadCount];
for (int i = 0; i < threadCount; i++)
{
    threads[i] = new Thread(() => processThread(startPoints[i], endPoints[i]));
    threads[i].Start();
    Console.WriteLine("Started for " + startPoints[i] + ", " + endPoints[i]); 
}

预期结果类似于

Processed for 1, 100
Processed for 101, 200
Processed for 201, 300
Processed for 301, 400
Processed for 401, 500
Processed for 501, 600
Processed for 601, 700
Processed for 701, 800
.....

依旧......但我得到的是:

Started for 0, 2500
Started for 2500, 5000
Processed for 5001, 5100
Processed for 5101, 5200
Processed for 5201, 5300
Processed for 5301, 5400
Processed for 5401, 5500
Processed for 5501, 5600
Processed for 5601, 5700
Processed for 5001, 5100
Started for 5000, 7500
Processed for 5001, 5100
Processed for 5101, 5200
Processed for 5201, 5300
Processed for 5301, 5400
Processed for 5401, 5500
Processed for 5501, 5600
Processed for 5601, 5700
Processed for 5701, 5800
Processed for 5801, 5900
Processed for 5901, 6000
Processed for 6001, 6100
Processed for 6101, 6200
Started for 7500, 10000
Processed for 6201, 6300
Processed for 6301, 6400
Processed for 6401, 6500
Processed for 6501, 6600
Processed for 5701, 5800

其中有许多重复值,并且在0-2500范围内没有。我也尝试过Task.Factory,得到了相同的结果。

对此的任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:2)

我运行你的代码并且在启动线程时实际上得到了一个索引超出范围的异常。这对我有用:

Thread[] threads = new Thread[threadCount];
for (int i = 0; i < threadCount; i++) {
    var start = startPoints[i];
    var end = endPoints[i];
    threads[i] = new Thread( () => processThread( start, end ) );
    threads[i].Start();
    Console.WriteLine( "Started for " + startPoints[i] + ", " + endPoints[i] );
}

问题可能是当线程访问代码中的startPoints[i]时,主线程中的i已经更改。

答案 1 :(得分:1)

我不会评论您的问题的正确解决方案,只是为了修复您的输出,您最后会错过这个以便在所有子项完成之前阻止主线程:

                Console.WriteLine("Started for " + startPoints[i] + ", " + endPoints[i]);
        }
        foreach (var thread in threads)
        {
            thread.Join();
        }

        Console.ReadKey();
    }

我在代码中修复了一件事:

            int count = i;
            threads[i] = new Thread(() =>
            {
                processThread(startPoints[count], endPoints[count]);
            });

防止在从子线程进行评估时i无效的潜在问题。

我还要说,除非你真的需要使用“旧的”.net线程,否则应该按照其他评论者的建议使用并行库或任务。

同样只是用Task方法重写(我保留了它,因为它更换了Thread with Task以便更好地说明)。

var factory = new TaskFactory();
        var tasks = new List<Task>();
        for (int i = 0; i < threadCount; i++)
        {
            int count = i;
            Task task = factory.StartNew(() =>
            {
                processThread(startPoints[count], endPoints[count]);
            });
            tasks.Add(task);
            Console.WriteLine("Started for " + startPoints[i] + ", " + endPoints[i]);
        }

        Task.WaitAll(tasks.ToArray());