zoukankan      html  css  js  c++  java
  • C#读书笔记:线程,任务和同步

    前言

    学习C#两个多月了,像当初实习做PHP开发一样,也是由着一个个Feature需求,慢慢掌握了很多相关的编程技巧。本次主要记录下学习C# 多线程的相关知识。

    参考书籍:《Csharp高级编程(第7版)》

    1.使用线程的原因

     

    不过运行多个线程也要注意一些问题:他们可以同时运行,但是如果线程访问相同的数据,就很容易出问题,必须实现同步机制

     2.理解线程

     线程是程序中独立的指令流。C#编写的程序都有一个入口点(即Main()方法),程序从该方法的第一条开始执行,直到方法返回为止。这种程序结构非常适合用于一个有任务序列的程序,但是程序常常需要同时完成多个任务。

    这就要用到多个线程,比如Word的拼写检查器的工作原理是这样的:一个线程等待用户输入,另一个线程进行后台搜索,第3个线程将写入的数据保存在临时文件中,第4个线程从Internet上下载其他数据。

    理解线程很重要的一点其实是理解线程和进程的关系:

     

    3.创建线程的方式

    • 异步委托

    创建线程的一种简单地方式是定义委托,并异步调用它。委托是方法的类型安全的引用,它使用线程池来完成异步任务。

    代码实例:

    使用投票的例子,并检查委托是否完成了它的任务。等待异步委托结果的四种方式:

    (1)轮询

    Delegate类提供了BeginInvoke()方法,通过其返回类型IAsyncResult ,可以获取委托的相关信息,并检验它是否完成了任务。只要委托没有完成其任务,程序的主线程就继续执行while循环。

    (2)等待句柄

    使用与IAsyncResult 相关联的等待句柄。使用AsyncWaitHandle属性可以访问等待句柄,该属性可以返回一个WaitHandle类型的对象,它可以等待委托线程完成其任务。

    (3)异步回调

    (4)Lambda表达式 

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Threading;
    using System.Diagnostics;
    
    namespace Wrox.ProCSharp.Threading
    {
        class Program
        {
            static int TakesAWhile(int data, int ms)
            {
                Console.WriteLine("TakesAWhile started");
                Thread.Sleep(ms);
                Console.WriteLine("TakesAWhile completed");
                return ++data;
            }
    
         //要从委托中调用这个方法,必须定义一个有相同参数和返回类型的的委托 public delegate int TakesAWhileDelegate(int data, int ms); static void Main() { // synchronous // TakesAWhile(1, 3000); TakesAWhileDelegate d1 = TakesAWhile; // (1)polling轮询 //IAsyncResult ar = d1.BeginInvoke(1, 3000, null, null); //while (!ar.IsCompleted) //{ // // doing something else // Console.Write("."); // Thread.Sleep(50); //} //int result = d1.EndInvoke(ar); //Console.WriteLine("result: {0}", result); // (2)wait handle //IAsyncResult ar = d1.BeginInvoke(1, 3000, null, null); //while (true) //{ // Console.Write("."); // if (ar.AsyncWaitHandle.WaitOne(50, false)) // { // Console.WriteLine("Can get the result now"); // break; // } //} //int result = d1.EndInvoke(ar); //Console.WriteLine("result: {0}", result); // (3)async callback //d1.BeginInvoke(1, 3000, TakesAWhileCompleted, d1); //for (int i = 0; i < 100; i++) //{ // Console.Write("."); // Thread.Sleep(50); //} //(4)Lambda expression:可以直接访问作用域外的变量d1,所以不需要把一个值赋予BeginInvoke()方法的最后一个参数 d1.BeginInvoke(1, 3000, ar => { int result = d1.EndInvoke(ar); Console.WriteLine("result: {0}", result); }, null); for (int i = 0; i < 100; i++) { Console.Write("."); Thread.Sleep(50); } } static void TakesAWhileCompleted(IAsyncResult ar) { if (ar == null) throw new ArgumentNullException("ar"); TakesAWhileDelegate d1 = ar.AsyncState as TakesAWhileDelegate; Trace.Assert(d1 != null, "Invalid object type"); int result = d1.EndInvoke(ar); Console.WriteLine("result: {0}", result); } } }

    运行结果:

    代码实例:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    
    namespace Wrox.ProCSharp.Threading
    {
        public class MyThread
        {
            private string data;
    
            public MyThread(string data)
            {
                this.data = data;
            }
    
            public void ThreadMain()
            {
                Console.WriteLine("Running in a thread, data: {0}", data);
            }
        }
    
    
    
        public struct Data
        {
            public string Message;
        }
    
    
        class Program
        {
            static void Main()
            {
                FirstThread();
    
                //var t1 = new Thread(Prio);
                //t1.Name = "First";
    
                //var t2 = new Thread(Prio);
                //t2.Name = "Second";
                //t1.Priority = ThreadPriority.Highest;
                //t2.Priority = ThreadPriority.Lowest;
    
                //t1.Start();
                //t2.Start();
    
                //var t1 = new Thread(ThreadMain);
                //t1.Name = "MyNewThread1";
                //t1.IsBackground = true;
                //t1.Start();
                //Console.WriteLine("Main thread ending now...");
    
                //var d = new Data { Message = "Info" };
                //var t2 = new Thread(ThreadMainWithParameters);
                //t2.Start(d);
    
                //var obj = new MyThread("info");
                //var t3 = new Thread(obj.ThreadMain);
                //t3.Start();
            }
    
            static void Prio()
            {
                for (int i = 0; i < 10000; i++)
                {
                    Console.WriteLine("{0}, {1}", Thread.CurrentThread.Name, i);
                }
            }
    
            static void ThreadMain()
            {
                Console.WriteLine("Thread {0} started", Thread.CurrentThread.Name);
                Thread.Sleep(3000);
                // Console.WriteLine("Running in the thread {0}, id: {1}.", Thread.CurrentThread.Name, Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine("Thread {0} completed", Thread.CurrentThread.Name);
            }
    
            static void ThreadMainWithParameters(object o)
            {
                Data d = (Data)o;
                Console.WriteLine("Running in a thread, received {0}", d.Message);
            }
    
            static void FirstThread()
            {
                new Thread(() => Console.WriteLine("Running in a thread, id: {0}", Thread.CurrentThread.ManagedThreadId)).Start();
    
                Console.WriteLine("This is the main thread, id: {0}", Thread.CurrentThread.ManagedThreadId);
            }
        }
    }
    

    运行结果:

    代码实例:

    using System;
    using System.Threading;
    
    namespace Wrox.ProCSharp.Threading
    {
        class Program
        {
            static void Main()
            {
                int nWorkerThreads;
                int nCompletionPortThreads;
                ThreadPool.GetMaxThreads(out nWorkerThreads, out nCompletionPortThreads);
                Console.WriteLine("Max worker threads: {0}, I/O completion threads: {1}", nWorkerThreads, nCompletionPortThreads);
    
                for (int i = 0; i < 5; i++)
                {
                    ThreadPool.QueueUserWorkItem(JobForAThread);
    
                }
    
                Thread.Sleep(3000);
            }
    
    
            static void JobForAThread(object state)
            {
                for (int i = 0; i < 3; i++)
                {
                    Console.WriteLine("loop {0}, running inside pooled thread {1}", i,
                       Thread.CurrentThread.ManagedThreadId);
                    Thread.Sleep(50);
                }
    
            }
        }
    }
    

    运行结果:

     代码实例:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.IO;
    
    namespace TaskSamples
    {
        class Program
        {
            static void Main()
            {
                // ParallelDemo();
    
                SimpleTask();
                // ContinuationTask();
                // ParentAndChild();
                // ResultsFromTasks();
    
                Thread.Sleep(5000);
    
                //ParentAndChild();
    
                // HierarchyTasks("c:\");
    
                //Parallel.f
                //Task t1 = new Task(() => Console.WriteLine("running in a task"));
                //Task t2 = new Task(() => Console.WriteLine("running in a task"));
    
                //for (int i = 0; i < 10; i++)
                //{
                //    Task t1 = new Task(o =>
                //    {
                //        Console.WriteLine("running in a task {0}", Thread.CurrentThread.ManagedThreadId);
                //        Thread.Sleep(500);
                //        Console.WriteLine("still running {0}", Thread.CurrentThread.ManagedThreadId);
                //    }, "data", TaskCreationOptions.None);
                //    // t1.RunSynchronously();
                //    t1.Start();
    
    
    
                //}
    
    
    
                //Console.WriteLine("start sleep main");
                //Thread.Sleep(3000);
                //Console.WriteLine("main thread");
            }
    
            static void ResultsFromTasks()
            {
                var t1 = new Task<Tuple<int,int>>(TaskWithResult, Tuple.Create<int, int>(8, 3));
                t1.Start();
                Console.WriteLine(t1.Result);
                t1.Wait();
                Console.WriteLine("result from task: {0} {1}", t1.Result.Item1, t1.Result.Item2);
            }
    
            static Tuple<int, int> TaskWithResult(object division)
            {
                Tuple<int, int> div = (Tuple<int, int>)division;
                int result = div.Item1 / div.Item2;
                int reminder = div.Item1 % div.Item2;
                Console.WriteLine("task creates a result...");
    
                return Tuple.Create<int, int>(result, reminder);
            }
    
            static void SimpleTask()
            {
                // using task factory
                TaskFactory tf = new TaskFactory();
                Task t1 = tf.StartNew(TaskMethod);
    
                // using the task factory via a task
                Task t2 = Task.Factory.StartNew(TaskMethod);
    
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
    
                // using Task constructor
                Task t3 = new Task(TaskMethod);
                // t3.Start();
                t3.RunSynchronously();
    
                Task t4 = new Task(TaskMethod, TaskCreationOptions.PreferFairness);
                t4.Start();
              
            }
    
            static void ContinuationTask()
            {
                Task t1 = new Task(DoOnFirst);
                Task t2 = t1.ContinueWith(DoOnSecond);
                Task t3 = t1.ContinueWith(DoOnSecond);
                Task t4 = t2.ContinueWith(DoOnSecond);          
                Task t5 = t1.ContinueWith(DoOnError, TaskContinuationOptions.OnlyOnFaulted);
                t1.Start();
    
    
                Thread.Sleep(5000);
    
            }
    
    
            static void DoOnFirst()
            {
                Console.WriteLine("doing some task {0}", Task.CurrentId);
                Thread.Sleep(3000);
            }
    
            static void DoOnSecond(Task t)
            {
                Console.WriteLine("task {0} finished", t.Id);
                Console.WriteLine("this task id {0}", Task.CurrentId);
                Console.WriteLine("do some cleanup");
                Thread.Sleep(3000);
            }
    
            static void DoOnError(Task t)
            {
                Console.WriteLine("task {0} had an error!", t.Id);
                Console.WriteLine("my id {0}", Task.CurrentId);
                Console.WriteLine("do some cleanup");
            }
    
            static void ParentAndChild()
            {
                Task parent = new Task(ParentTask);
                parent.Start();
                Thread.Sleep(2000);
                Console.WriteLine(parent.Status);
                Thread.Sleep(4000);
                Console.WriteLine(parent.Status);
    
            }
            static void ParentTask()
            {
                Console.WriteLine("task id {0}", Task.CurrentId);
                Task child = new Task(ChildTask); // , TaskCreationOptions.DetachedFromParent);
                child.Start();
                Thread.Sleep(1000);
                Console.WriteLine("parent started child");
               // Thread.Sleep(3000);
            }
            static void ChildTask()
            {
                // Console.WriteLine("task id {0}, parent: {1}", Task.Current.Id, Task.Current.Parent.Id);
                Console.WriteLine("child");
                Thread.Sleep(5000);
                Console.WriteLine("child finished");
            }
    
            static void TaskMethod()
            {
                Console.WriteLine("running in a task");
                Console.WriteLine("Task id: {0} {1}", Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
            }
    
            static void ParallelDemo()
            {
                // Parallel.For(0, 5, i => Console.WriteLine(i));
                Parallel.For<string>(0, 20, () => "abcd",
                    (x, ls, str) =>
                    {
                        Console.WriteLine(x);
                        return "defg";
                    },
                        (str) =>
                        {
                            Console.WriteLine("action {0}", str);
                        });
    
                ParallelOptions po = new ParallelOptions();
    
    
    
                   
            }
    
    
    
            //static void ParentAndChild()
            //{
            //    TaskFactory factory = new TaskFactory();
            //    var t1 = factory.StartNew(() =>
            //        {
            //            Console.WriteLine("parent task {0}", Task.CurrentId);
    
            //            factory.StartNew(() =>
            //                {
            //                    Console.WriteLine("child task {0}", Task.CurrentId);
            //                    Thread.Sleep(2000);
            //                    Console.WriteLine("finished child");
            //                }, TaskCreationOptions.AttachedToParent);
    
            //            Console.WriteLine("finished parent");
            //        });
    
            //    t1.Wait();
    
            //}
    
    
        }
    }
    

    运行结果:

    代码实例:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace Wrox.ProCSharp.Threading
    {
        class Program
        {
            static void Main()
            {
                //ParallelFor();
                //ParallelForeach();
                ParallelInvoke();
            }
    
            static void ParallelInvoke()
            {
                //并行运行多个任务:Parallel.Invoke()方法允许传递一个Action委托数组,其中指定应运行的方法
                Parallel.Invoke(Foo, Bar);
            }
    
            static void Foo()
            {
                Console.WriteLine("foo");
            }
    
            static void Bar()
            {
                Console.WriteLine("bar");
            }
    
            static void ParallelForeach()
            {
                string[] data = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve"};
    
                //异步方式遍历
                ParallelLoopResult result =
                    Parallel.ForEach<string>(data, s =>
                        {
                            Console.WriteLine(s);
                        });
    
    
                Parallel.ForEach<string>(data,
                    (s, pls, l) =>
                    {
                        Console.WriteLine("{0} {1}", s, l);
    
                    });
    
            }
    
            static void ParallelFor()
            {
                //ParallelLoopResult result =
                //    Parallel.For(0, 10, i =>
                //        {
                //            Console.WriteLine("{0}, task: {1}, thread: {2}", i,
                //               Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
                //            Thread.Sleep(10);
    
                //        });
                //Console.WriteLine(result.IsCompleted);
    
                //ParallelLoopResult result =
                //    Parallel.For(10, 40, (int i, ParallelLoopState pls) =>
                //        {
                //            Console.WriteLine("i: {0} task {1}", i, Task.CurrentId);
                //            Thread.Sleep(10);
                //            if (i > 15)
                //                pls.Break();
                //        });
                //Console.WriteLine(result.IsCompleted);
                //Console.WriteLine("lowest break iteration: {0}", result.LowestBreakIteration);
    
    
                Parallel.For<string>(0, 20,
                    () =>
                    {
                        // invoked once for each thread
                        Console.WriteLine("init thread {0}, task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
                        return String.Format("t{0}", Thread.CurrentThread.ManagedThreadId);
                    },
                    (i, pls, str1) =>
                    {
                        // invoked for each member
                        Console.WriteLine("body i {0} str1 {1} thread {2} task {3}", i, str1,
                            Thread.CurrentThread.ManagedThreadId,
                            Task.CurrentId);
                        Thread.Sleep(10);
                        return String.Format("i {0}", i);
    
                    },
                    (str1) =>
                    {
                        // final action on each thread
                        Console.WriteLine("finally {0}", str1);
                    });
    
    
    
            }
        }
    }
    

    运行结果:

    代码实例:

      

      

      

    ps:在运行书中附带的sample时,报错:

    经查证,发现这是由于StartupUri中的内容与窗口名称不一致所导致。

    这部分的知识可以参考一篇译文:WPF教程(十)使用App.xaml

  • 相关阅读:
    高级特性(4)- 数据库编程
    UVA Jin Ge Jin Qu hao 12563
    UVA 116 Unidirectional TSP
    HDU 2224 The shortest path
    poj 2677 Tour
    【算法学习】双调欧几里得旅行商问题(动态规划)
    南洋理工大学 ACM 在线评测系统 矩形嵌套
    UVA The Tower of Babylon
    uva A Spy in the Metro(洛谷 P2583 地铁间谍)
    洛谷 P1095 守望者的逃离
  • 原文地址:https://www.cnblogs.com/carsonzhu/p/7207556.html
Copyright © 2011-2022 走看看