C#.Net - 线程在循环中抓取相同的文件

时间:2014-01-27 23:58:42

标签: c# .net multithreading ocr

我正在尝试设计一个程序,该程序使用外部OCR应用程序将图像翻转直到其正面朝上。所有图像位置都保存在文件[]中。

问题是,一次做一个文件太慢,无法处理我的数万张图像。我需要启动OCR程序的多个实例来同时扫描多个图像。

我糟糕的实现如下:

public Program(string[] files)
    {
        for(int i = 0; i < files.Length; i++)
        {
            ThreadStart start = () => {flip(files[i]);};
            Thread t = new Thread(start);
            t.Start();
            if(i % 5 == 0)
            {
                t.Join();
            }
        }
    }

该代码应该启动5个OCR程序实例。在每五分之一,它等待线程关闭然后继续。这应该充当缓冲区。

然而,正在发生的是重复文件被传递到OCR程序而不是每次迭代的不同文件。不同的线程正在抓取同一个文件。当OCR应用程序的不同实例在同一文件上工作时,这会导致崩溃。

有没有人知道最新情况,或者我知道一种完全不同的做法?

2 个答案:

答案 0 :(得分:3)

您遇到了一个名为访问修改后的闭包的问题。 i的值随着线程的开始而变化。更改代码以改为使用局部变量。

        for (int i = 0; i < args.Length; i++)
        {
            int currenti = i;
            ThreadStart start = () => { flip(files[currenti]); };
            Thread t = new Thread(start);
            t.Start();
            if (i % 5 == 0)
            {
                t.Join();
            }
        }

答案 1 :(得分:2)

问题是你的lambda表达式正在捕获变量 i,而不是它循环迭代的值。

有两种选择:

抓取副本

for (int i = 0; i < files.Length; i++)
{
    int copy = i;
    ThreadStart start = () => flip(files[copy]); // Braces aren't needed
    ...
}

仅使用foreach - C#5!

这对你的情况没有多大帮助,因为你加入了每五个项目,所以你需要索引,但是如果没有那个位和< / em>如果你使用的是C#5,你可以使用:

foreach (var file in files)
{
    ThreadStart start = () => flip(file);
    ...
}

请注意,在C#5之前,这可能会遇到完全相同的问题。

有关此问题的详细信息,请参阅Eric Lippert的博文(part one; part two)。