namespace ThPool
{
class Program
{
private static long val = 0;
private static string obj = string.Empty;
static void Main(string[] args)
{
Thread objThread1 = new Thread(new ThreadStart(IncrementValue));
objThread1.Start();
Thread objThread2 = new Thread(new ThreadStart(IncrementValue));
objThread2.Start();
objThread1.Join();
objThread2.Join();
Console.WriteLine("val=" + val + " however it should be " + (10000000 + 10000000));
Console.ReadLine();
}
private static void IncrementValue()
{
for (int i = 0; i < 10000000; i++)
{
Monitor.Enter(obj);
val++;
Monitor.Exit(obj);
}
}
}
}
如何使用ThreadPool
类代替线程&amp;显示器?
答案 0 :(得分:4)
有两种方法可以使用线程池。对于您的任务,您应该查看以下内容。
QueueUserWorkItem
,它只需要一个委托来运行。缺点是你几乎无法控制工作。委托不能返回值,并且您不知道运行何时完成。 BeginInvoke
/ EndInvoke
界面。这会调度代码以在线程池线程上运行。您可以通过IAsyncResult
返回的BeginInvoke
句柄查询状态,您可以通过EndInvoke
获取结果(以及工作线程上的任何异常)。 要正确使用Enter
上的Exit
/ Monitor
,您必须确保始终调用Exit
。因此,您应将Exit
调用放在finally块中。
但是,如果您不需要为Enter
提供超时值,那么只使用lock
关键字会更好,它会编译成一组{{1} }和Enter
来电。
答案 1 :(得分:2)
EventWaitHandle[] waitHandles = new EventWaitHandle[2];
for(int i = 0; i < 2; i++)
{
waitHandles[i] = new AutoResetEvent(false);
ThreadPool.QueueUserWorkItem(state =>
{
EventWaitHandle handle = state as EventWaitHandle;
for(int j = 0; j < 10000000; j++)
{
Interlocked.Increment(ref val); //instead of Monitor
}
handle.Set();
}, waitHandles[i]);
}
WaitHandle.WaitAll(waitHandles);
Console.WriteLine("val=" + val + " however it should be " + (10000000 + 10000000));
答案 2 :(得分:1)
你应该研究ThreadPool.QueueUserWorkItem()
。它需要一个在线程池线程上运行的委托,传入一个状态对象。
即
string fullname = "Neil Barnwell";
ThreadPool.QueueUserWorkItem(state =>
{
Console.WriteLine("Hello, " + (string)state);
}, fullname);
不要被Control.BeginInvoke()
混淆。这将封送对创建控件的线程的调用,以防止跨线程调用更新控件的问题。如果您想在Windows窗体上使用简单的多线程,请查看BackgroundWorker。
答案 3 :(得分:0)
您可以使用BeginInvoke
,EndInvoke
。它在幕后使用线程池,但编程更容易。见这里:
答案 4 :(得分:0)
除了最简单的事情之外,不要使用线程池。实际上,获取线程池线程上的锁是非常危险的。但是,您可以安全地使用Interlocked API。