.NET线程池正在使用AutoResetEvent进行同步
本文关键字:AutoResetEvent 同步 线程 NET | 更新日期: 2023-09-27 18:22:19
下面是我使用的代码。主线程等待线程池线程执行。我使用了AutoResetEvent(WaitHandle),但我真的很惊讶我偏离了目标,因为代码的行为没有达到预期。
我有两个同心的for循环,其中Threadpool在内部循环中,预计对于外部循环的每次迭代,都应该处理所有内部循环值。使用内部循环外的AutoResetEvent WaitOne调用使主线程等待,内部循环是一个静态变量,在外部循环的每次迭代中重置为内部循环的最大值,并在线程上的方法调用中使用Interlock递减。线程用于调用AutoResetEventSet。然而,即使我期望静态变量在每个内部循环后显示值0,它也不会。我的代码中有什么问题?我有什么更好的选择来完成任务?事实上,由于值的混淆,主线程似乎并没有真正等待Threadpool线程。
using System;
using System.Threading;
namespace TestThreads
{
class Program
{
private static int threadingCounter = 0;
private static readonly object lockThreads = new Object();
private AutoResetEvent areSync = new AutoResetEvent(true);
// <param name="args"></param>
static void Main(string[] args)
{
Program myProgram = new Program();
try
{
try
{
for (int outer = 0; outer < 1000; outer++)
{
threadingCounter = 500;
try
{
for (int inner = 0; inner < 500; inner++)
{
ThreadPool.QueueUserWorkItem(new
WaitCallback(myProgram.ThreadCall), inner);
}
}
catch (Exception ex)
{
Console.WriteLine("Exception :: " + ex.Message);
}
finally
{
myProgram.areSync.WaitOne();
}
if(threadingCounter != 0)
Console.WriteLine("In Loop1, Thread Counter :: " +
threadingCounter);
}
}
catch (Exception ex)
{
Console.WriteLine("Exception :: " + ex.Message);
}
}
catch(Exception ex)
{
Console.WriteLine("Exception :: " + ex.Message);
}
finally
{
threadingCounter = 0;
if (myProgram.areSync != null)
{
myProgram.areSync.Dispose();
myProgram.areSync = null;
}
}
}
public void ThreadCall(object state)
{
try
{
int inner = (int)state;
Thread.Sleep(1);
}
catch (Exception ex)
{
Console.WriteLine("Exception :: " + ex.Message);
}
finally
{
Interlocked.Decrement(ref threadingCounter);
if (threadingCounter <= 0)
areSync.Set();
}
}
}
}
您已初始化AutoResetEvent,初始状态为signaled(true),这将允许首次调用
myProgram.areSync.WaitOne();
在没有阻塞的情况下继续,所以它继续到外循环,并再次将执行排队到Threadpool,因此结果混乱不堪。这是非常清楚的。
将您的代码更新为
private AutoResetEvent areSync = new AutoResetEvent(false);
以获得预期结果。希望这对有帮助
我会用这样的东西重构它。这假设你想在内部循环的后台线程中做一些事情,在继续下一个外部循环之前完成每一个,避免混乱的异常处理,同时仍然捕获处理过程中发生的异常,这样你就可以在内部和外部循环的处理完成后处理这些异常。
// track exceptions that occurred in loops
class ErrorInfo
{
public Exception Error { get; set; }
public int Outer { get; set; }
public int Inner { get; set; }
}
class Program
{
static void Main(string[] args)
{
// something to store execeptions from inner thread loop
var errors = new ConcurrentBag<ErrorInfo>();
// no need to wrap a try around this simple loop
// unless you want an exception to stop the loop
for (int outer = 0; outer < 10; outer++)
{
var tasks = new Task[50];
for (int inner = 0; inner < 50; inner++)
{
var outerLocal = outer;
var innerLocal = inner;
tasks[inner] = Task.Factory.StartNew(() =>
{
try
{
Thread.Sleep(innerLocal);
if (innerLocal % 5 == 0)
{
throw new Exception("Test of " + innerLocal);
}
}
catch (Exception e)
{
errors.Add(new ErrorInfo
{
Error = e,
Inner = innerLocal,
Outer = outerLocal
});
}
});
}
Task.WaitAll(tasks);
}
Console.WriteLine("Error bag contains {0} errors.", errors.Count);
Console.ReadLine();
}
}