我在下面写了一个示例程序。
class Program
{
static int x = 2;
static void Main(string[] args)
{
Console.WriteLine("Thread ID {0} and Main Called!", Thread.CurrentThread.ManagedThreadId);
ThreadPool.QueueUserWorkItem(Count, args);
ThreadPool.QueueUserWorkItem(Count2, args);
Console.WriteLine("Thread ID {0} and Main Done!", Thread.CurrentThread.ManagedThreadId);
Console.ReadLine();
}
static void Count(object args)
{
for (int i = 0; i < 10; i++)
{
x = x + 2;
Console.WriteLine("Thread ID {0} AND Count 1: " + x, Thread.CurrentThread.ManagedThreadId);
}
}
static void Count2(object args)
{
for (int i = 0; i < 10; i++)
{
x = x + 2;
Console.WriteLine("Thread ID {0} AND Count 2: " + x, Thread.CurrentThread.ManagedThreadId);
}
}
}
当使用ThreadPool.QueueUserWorkItem调用Count方法时,我注意到Main在Count方法完成之前完成,而Count2方法与Count Method纠结在一起。
Main(和Count2)是否还要等到Count方法完成?我不想使用锁也不想使用Thread.Sleep(因为我不知道Count操作需要多长时间)。我已经读过某处异步调用或WAIT用于这段时间。
有什么想法吗?
答案 0 :(得分:4)
我将介绍两种模式。这两种模式都具有高度可扩展性,因为它们可以处理数百甚至数千个同步工作项。您必须完全遵循模式。任何偏差都可能导致事件信号与等待事件之间的竞争状况。我已经在循环的上下文中呈现了模式以概括它,但在您的情况下,您将使用对ThreadPool.QueueUserWorkItem
的两次单独调用替换循环。
第一个模式需要CountdownEvent类,它可以在.NET 4.0中使用,也可以作为Reactive Extensions下载的一部分。
var finished = new CountdownEvent(1);
for (int i = 0; i < NUM_WORK_ITEMS; i++)
{
finished.AddCount();
ThreadPool.QueueUserWorkItem(
(state) =>
{
try
{
// Your work item code goes here.
// Call Count, Count2, or whatever.
}
finally
{
finished.Signal();
}
});
}
finished.Signal();
finished.WaitOne();
以下模式适用于任何版本的.NET Framework 1 。它虽然不那么优雅。
int count = 1;
var finished = new ManualResetEvent(false);
for (int i = 0; i < NUM_WORK_ITEMS; i++)
{
Interlocked.Increment(ref count);
ThreadPool.QueueUserWorkItem(
(state) =>
{
try
{
// Your work item code goes here.
// Call Count, Count2, or whatever.
}
finally
{
if (Interlocked.Decrement(ref count) == 0) finished.Set();
}
});
}
if (Interlocked.Decrement(ref count) == 0) finished.Set();
finished.WaitOne();
1 当然,如果使用更早的版本,你必须用匿名方法替换lambda表达式,甚至是真正的方法。
答案 1 :(得分:1)
我认为AutoResetEvent就是你的目标
**编辑:** 这是修改后的代码(未经测试)。我在本例中使用了AutoResetEvent而不是Manual
class Program
{
static int x = 2;
// Define an array with two AutoResetEvent WaitHandles.
static WaitHandle[] waitHandles = new WaitHandle[]
{
new AutoResetEvent(false),
new AutoResetEvent(false)
};
static void Main(string[] args)
{
Console.WriteLine("Thread ID {0} and Main Called!", Thread.CurrentThread.ManagedThreadId);
ThreadPool.QueueUserWorkItem(new WaitCallback(Count), waitHandles[0]);
ThreadPool.QueueUserWorkItem(new WaitCallback(Count2), waitHandles[1]);
WaitHandle.WaitAll(waitHandles);
Console.WriteLine("Thread ID {0} and Main Done!", Thread.CurrentThread.ManagedThreadId);
Console.ReadLine();
}
static void Count(object args)
{
AutoResetEvent are = (AutoResetEvent)args;
for (int i = 0; i < 10; i++)
{
x = x + 2;
Console.WriteLine("Thread ID {0} AND Count 1: " + x, Thread.CurrentThread.ManagedThreadId);
}
are.Set();
}
static void Count2(object args)
{
AutoResetEvent are = (AutoResetEvent)args;
for (int i = 0; i < 10; i++)
{
x = x + 2;
Console.WriteLine("Thread ID {0} AND Count 2: " + x, Thread.CurrentThread.ManagedThreadId);
}
are.Set();
}
}