1

List<int>呼び出された を受け入れるメソッドがありますDoWork。私は巨大な List<int> Idsを持っています。膨大なリストを 4 つのサブリストに分割します。

List<List<int>> t = (List<List<int>>)SplitColumn<int>(Ids);

リストをサブリストに分割するSplitColumnための回答からわずかに変更されています)。

プログラムを一時停止tしてデバッガーで調べたところ、期待どおりに 4 つのリストが分割されています。

次に、4 つのスレッド (サブリストごとに 1 つ) を生成しようとしています。私が問題を抱えている部分は、4 つのリストを渡すことです。範囲外の問題が発生しています。ここで何が起こっているのかわかりません:

        List<Thread> threads = new List<Thread>();

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

        foreach (Thread thread in threads)
        {
            thread.Start();
        }


        foreach (Thread thread in threads)
        {
            thread.Join();
        }
4

5 に答える 5

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])));
    }
于 2012-10-12T20:23:27.997 に答える
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]。良くない!

于 2012-10-12T20:23:12.133 に答える
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]);
    }
于 2012-10-12T20:24:58.353 に答える
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
  }
}
于 2012-10-12T20:42:14.607 に答える
0

Henk Holterman が指摘するように、ループ変数を閉じています。代わりに私がすることはこれです:

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

有害と見なされるループ変数のクローズも参照してください。

于 2012-10-12T20:41:47.853 に答える