将列表传递给线程

时间:2012-10-12 20:19:19

标签: c# multithreading .net-4.0

我有一个方法接受名为List<int>的{​​{1}}。我有一个巨大的 DoWork。我将这个庞大的列表分成了4个子列表:

List<int> Ids

List<List<int>> t = (List<List<int>>)SplitColumn<int>(Ids); 稍微修改了splitting a list into sub lists的答案。

我暂停了程序,并使用调试器检查了SplitColumn,它是按照我的预期完全划分的四个列表。

然后,我正在尝试做的是产生四个线程(每个子列表一个)。我遇到麻烦的部分是通过四个列表。我遇到了问题,我不确定这里发生了什么:

t

5 个答案:

答案 0 :(得分:8)

这是一个经典的,称为捕获循环变量。

在此代码中,所有线程共享相同的变量i。当线程运行时,主线程将产生i == t.Count,因此范围异常。

    for(int i = 0; i < t.Count; i++) 
    {
        threads.Add(new Thread(() => DoWork(t[i])));
    }

修复它:

    for(int i = 0; i < t.Count; i++) 
    {
        int copy = i;
        threads.Add(new Thread(() => DoWork(t[copy])));
    }

答案 1 :(得分:3)

在这种情况下,捕获的变量不是你的朋友。尝试:

        for(int i = 0; i < t.Count; i++) 
        {
            int j=i;
            threads.Add(new Thread(() => DoWork(t[j])));
        }

当原作运行完成时,i==t.Count发生了什么。当DoWork执行时,您实际上正在执行t[t.Count]。不好!<​​/ p>

答案 2 :(得分:0)

您可以在启动线程时传入对象。因此,创建一个DoWork的重载,它接收一个普通的旧对象。然后进行下面的修改。

    for(int i = 0; i < t.Count; i++) 
    {
        threads.Add(new Thread(DoWork));
    }

    foreach (Thread thread in threads)
    {
        thread.Start([your list right there]);
    }

答案 3 :(得分:0)

正如Henk Holterman指出的那样,你正在关闭循环变量。我会做的是:

List<Thread> threads = t
    .Select(x => new Thread(() => DoWork(x)))
    .ToList();

另见Closing over the loop variable considered harmful

答案 4 :(得分:0)

您可以将复杂类型发送到线程

public string FileSource;
public string FileName;
public ThreadPriority Priority;

public ThreadInfo(string File, ThreadPriority priority)
{
   FileSource = File;
   FileName = Path.GetFileNameWithoutExtension(File);
   Priority = priority;
}

static void Main()
{
   ThreadInfo ti = null;
   try
   {
      ti = new ThreadInfo(FileName, ThreadPriority.Normal);
      ThreadPool.QueueUserWorkItem(ThreadImageProcess.doWork, ti);
   }
   catch (Exception error)
   {
      MyEventLog.WriteEntry("Error creating Thread Pool: "+ error.StackTrace, EventLogEntryType.Error, (int)ImageProcess.MyEventID.ProcessFile, (int)ImageProcess.MyErrorCategory.Information, null);
   }
   finally
   {
      if (ti != null)
          ti = null;
   }
}

public static void doWork(object sender)
{
  string FileName = "";
  try
  {
     Thread.CurrentThread.Priority = (sender as ThreadInfo).Priority;
     FileName = (sender as ThreadInfo).FileSource;
  }
  catch (Exception error)
  {
     //send some message
  }
}