如何使用ThreadPool类

时间:2009-02-01 12:21:52

标签: c#

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;显示器?

5 个答案:

答案 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)

您可以使用BeginInvokeEndInvoke。它在幕后使用线程池,但编程更容易。见这里:

http://msdn.microsoft.com/en-us/library/2e08f6yc.aspx

答案 4 :(得分:0)

除了最简单的事情之外,不要使用线程池。实际上,获取线程池线程上的锁是非常危险的。但是,您可以安全地使用Interlocked API。