C# 基本线程池问题

C# 基本线程池问题,c#,.net-2.0,threadpool,C#,.net 2.0,Threadpool,让我先声明一下,我对多线程非常陌生,可能遗漏了一些明显的东西 我目前正在使用下面的代码来处理目录中的所有文件。我的问题是,如果一个线程能够完成,减量numFilesLeft,并发现它等于0,因为下一个项目没有被添加为工作项目,也不是因为所有文件都已被处理?如果这是可能的,什么是标准的方法来确保它不会发生 谢谢你抽出时间 List<Bar> bars = new List<Bar>(); int numFilesLeft = 0; ManualResetEvent isWo

让我先声明一下,我对多线程非常陌生,可能遗漏了一些明显的东西

我目前正在使用下面的代码来处理目录中的所有文件。我的问题是,如果一个线程能够完成,减量
numFilesLeft
,并发现它等于0,因为下一个项目没有被添加为工作项目,也不是因为所有文件都已被处理?如果这是可能的,什么是标准的方法来确保它不会发生

谢谢你抽出时间

List<Bar> bars = new List<Bar>();
int numFilesLeft = 0;
ManualResetEvent isWorkDone = new ManualResetEvent(false);

foreach (string dirName in Directory.GetDirectories(@"c:\Temp"))
{
    foreach (string file in Directory.GetFiles(dirName))
    {
        string temp = file;
        Interlocked.Increment(ref numFilesLeft);
        ThreadPool.QueueUserWorkItem(delegate
        {
            try
            {
                List<Bar> results = Process(File.ReadAllText(temp));
                if (results.Count > 0)
                {
                    lock (bars) bars.AddRange(results);
                }
            }
            finally
            {
                if (Interlocked.Decrement(ref numFilesLeft) == 0)
                {
                    isWorkDone.Set();
                }
            }
        });
    }
}

isWorkDone.WaitOne();
isWorkDone.Close();
列表栏=新列表();
int numFilesLeft=0;
ManualResetEvent isWorkDone=新的ManualResetEvent(错误);
foreach(Directory.GetDirectories(@“c:\Temp”)中的字符串dirName)
{
foreach(Directory.GetFiles(dirName))中的字符串文件)
{
字符串temp=文件;
联锁增量(参考numFilesLeft);
ThreadPool.QueueUserWorkItem(委托
{
尝试
{
列表结果=进程(File.ReadAllText(temp));
如果(results.Count>0)
{
锁定(条)条。添加范围(结果);
}
}
最后
{
if(联锁减量(参考numFilesLeft)==0)
{
isWorkDone.Set();
}
}
});
}
}
isWorkDone.WaitOne();
isWorkDone.Close();

是的,这是可能的。通常的诀窍是再增加一个计数,以便对项目本身进行排队操作:

List<Bar> bars = new List<Bar>();
int numFilesLeft = 0;
ManualResetEvent isWorkDone = new ManualResetEvent(false);

Interlocked.Increment(ref numFilesLeft);
try
{
foreach (string dirName in Directory.GetDirectories(@"c:\Temp"))
{
    foreach (string file in Directory.GetFiles(dirName))
    {
        string temp = file;
        Interlocked.Increment(ref numFilesLeft);
        ThreadPool.QueueUserWorkItem(delegate
        {
            try
            {
                 ...
            }
            finally
            {
                if (Interlocked.Decrement(ref numFilesLeft) == 0)
                {
                    isWorkDone.Set();
                }
            }
        });
    }
}
}
finally
{
 if (0 == Interlocked.Decrement(ref numFilesLeft))
 {
   isWorkDone.Set ();
 }
}

...
列表栏=新列表();
int numFilesLeft=0;
ManualResetEvent isWorkDone=新的ManualResetEvent(错误);
联锁增量(参考numFilesLeft);
尝试
{
foreach(Directory.GetDirectories(@“c:\Temp”)中的字符串dirName)
{
foreach(Directory.GetFiles(dirName))中的字符串文件)
{
字符串temp=文件;
联锁增量(参考numFilesLeft);
ThreadPool.QueueUserWorkItem(委托
{
尝试
{
...
}
最后
{
if(联锁减量(参考numFilesLeft)==0)
{
isWorkDone.Set();
}
}
});
}
}
}
最后
{
如果(0==联锁减量(参考numFilesLeft))
{
isWorkDone.Set();
}
}
...
1。 我的问题是,这是否会发生 一根线可能完成, 减小numFilesLeft,并找到它 等于0,因为下一项 尚未作为工作项添加,并且 不是因为所有的文件都被删除了 处理

对。因为我们不知道线程何时开始处理

2. 如果这是可能的,那么结果会是什么 确保其不发生故障的标准方法 发生了什么

我们可以使用ManualResetEvent数组,然后在主线程中等待所有线程完成它们的工作

//假设您获得了目录中的文件数

  var fileCount = 10;

 ManualResetEvent[] waitHandles = new  ManualResetEvent[fileCount];
枚举文件并像您所做的那样创建每个线程。此外,将每个ManualResetEvent作为线程状态传递给初始化的每个线程

 ......
     ThreadPool.QueueWorkItem(ProcessFile, waitHandles[i]);
     .....
在ProcessFile()方法中,重新获得ManualResetEvent

   void ProcessFile(object stateInfo)
{
     var waitHandle = stateInfo as ManualResetEvent;
    //Do your work here
   
   //finished. Call Reset()
  waitHandle.Reset()
}
   
在主线程中,我们全部等待

 WaitHandle.WaitAll(waitHandles);
这将确保在主线程终止之前处理所有文件


希望有帮助。

这实际上与我以前使用的类似,但我遇到了WaitAll的限制,一次只能等待64个句柄。谢谢。这似乎是一个很好的解决方案。