11月 04

.NET 4为了简化多线程编程,提供了System.Threading.Tasks命名空间中的类来帮助开发者进行多线程编程,其中,Task类用来表示一个线程。最简单的Task类接受一个Action委托作为要执行的方法,调用Start方法开始在另一个线程中运行。例如:
两句输出的顺序是不一定的,但是很有可能是:

Main Thread
Write from another thread

也可以使用Task.Factory.StartNew方法,这个方法会构造一个Task并且立刻开始运行,相当于将Task的构造函数和Start方法连在一起执行。

Task类还有一个构造函数可以接受Action<object>委托,用来向Action委托传递参数:

        static void Main(string[] args)
        {
            List<Task> list = new List<Task>();
            for (int i = 0; i <10; i++)
            {
                Task t = new Task(obj =>
                {
                    int total = (int)obj;
                    for (int index = 0; index < total; index++)
                    {
                        Thread.Sleep(100);
                        Console.WriteLine("Thread No " + obj);
                    }
                }, i);
                list.Add(t);
            }
            for (int i = 0; i < list.Count; i++)
            {
                list[i].Start();
            }
            Console.ReadLine();
        }

输出的结果类似于:

Thread No 2
Thread No 1
Thread No 3
Thread No 0
Thread No 4

可以使用Task<T>类来获得返回值,T是返回值的类型,例如:

        static void Main(string[] args)
        {
            Task<int> t = new Task<int>(() =>
            {
                int s = 0;
                for (int i = 0; i < 1000; i++)
                { 
                    Thread.Sleep(1);
                    s += i;
                }
                return s;
            }); 
            t.Start();
            Console.WriteLine(t.Result);
            Console.WriteLine("I'm computing");
            Console.WriteLine(t.Result);
            Console.ReadLine();
        }

结果如下

499500
I'm computing
499500

在访问t.Result的时候,.net 会保证此时Task的代码已经执行完毕,Result已经获得,否则该线程会阻塞,直到Result计算完毕。接龙大全Task库提供了一种主动终止线程的方法,先创建一个CancellationTokenSource,将其Token属性通过Task构造函数传进去,在Task内部轮询token的IsCancellationReqeusted属性,如果检测到为true,则主动终止线程。在父线程内调用tokenSource的Cancel方法,可以终止线程。注意,这是线程主动终止自己的方法,必须在Task内的代码自己终止,.NET不会强行终止task线程,即使父线程调用了tokenSource的Cancel方法。

例如下面的代码,如果在else语句块内没有break语句,子线程是不会终止的。

        static void Main(string[] args)
        {
            CancellationTokenSource tks = new CancellationTokenSource();
            CancellationToken token = tks.Token;
            long i = 0;
            Task task = new Task(() =>
            {
                while (true)
                {
                    if (!token.IsCancellationRequested)
                        i++;
                    else
                    {
                        Console.WriteLine("Task is canceled, it looped " + i + " times");
                        break;
                    }
                }
            }, token);
            task.Start();
            Console.WriteLine("Press Enter to Cancel task");
            Console.ReadLine(); 
            tks.Cancel(); 
            Console.ReadLine();
        }

还可以通过CancellationToken的Register方法给token注册一个委托,当调用tokenSource的Cancel方法的时候,这个委托会被执行。这个委托是在调用Cancel方法的线程中执行的。

        token.Register(() => { Console.WriteLine("Delegate Invoked"); });

要挂起当前线程,等待一个线程执行完成,可以使用执行线程的Wait()方法,Wait方法有一些重载方法,可以指定等待的时间等,例如:

        static void Main(string[] args)
        {
            Task t1 = new Task(() =>
            {
                Console.WriteLine("Task 1 Starts...");
                Thread.Sleep(3000);
                Console.WriteLine("Task1 Ends");
            });
            t1.Start(); Task t2 = new Task(() =>
             {
                 Console.WriteLine("Task2 Starts...");
                 t1.Wait();
                 Console.WriteLine("Task2 Ends");
             });
            Task t3 = new Task(() =>
            {
                Console.WriteLine("Task 3 is waiting Task1 for 1 second...");
                bool finished = t1.Wait(1000);
                if (finished)
                    Console.WriteLine("T1 is finished");
                else
                    Console.WriteLine("T1 is not finished");
            });
            t2.Start();
            t3.Start();
            Console.ReadLine();
        }

结果如下

Task 1 Starts...
Task 3 is waiting Task1 for 1 second...
Task2 Starts...
T1 is not finished
Task1 Ends
Task2 Ends

如果要等待的话参考Task4

        static void Main(string[] args)
        {
            Task t1 = new Task(() =>
            {
                Console.WriteLine("Task 1 Starts...");
                Thread.Sleep(3000);
                Console.WriteLine("Task1 Ends");
            });
            t1.Start(); Task t2 = new Task(() =>
             {
                 Console.WriteLine("Task2 Starts...");
                 t1.Wait();
                 Console.WriteLine("Task2 Ends");
             });
            Task t3 = new Task(() =>
            {
                Console.WriteLine("Task 3 is waiting Task1 for 1 second...");
                bool finished = t1.Wait(1000);
                if (finished)
                    Console.WriteLine("T1 is finished");
                else
                    Console.WriteLine("T1 is not finished");
            });

            Task t4 = new Task(() =>
            {
                Console.WriteLine("Waiting for all");
                Task.WaitAll(t1, t2, t3);
                Console.WriteLine("Task4 Ends");
            });
            t4.Start(); 
            t2.Start();
            t3.Start();
            Console.ReadLine();
        }

结果如下

Task 1 Starts...
Task2 Starts...
Waiting for all
Task 3 is waiting Task1 for 1 second...
T1 is not finished
Task1 Ends
Task2 Ends
Task4 Ends

还有一个Task.WaitAny,可以等待一组线程中的任何一个方法执行完毕,用法类似。

转自:http://www.cnblogs.com/yinzixin/archive/2011/11/04/2235233.html   

written by ocean