我有一个方法接受名为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
答案 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();
答案 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
}
}