zoukankan      html  css  js  c++  java
  • C# 多线程

    一、线程之间共享变量:

      1. 同对象中的变量(线程内部方法)
    class ThreadTest {
        bool done;
        static void Main() {
            ThreadTest tt = new ThreadTest(); // Create a common instance
            new Thread(tt.Go).Start();
            tt.Go();
        }
        // Note that Go is now an instance method
        void Go() {
            if (!done) {
                done = true;
                Console.WriteLine("Done");
            }
        }
    }
      1. 静态变量
    class ThreadTest {
        static bool done; // Static fields are shared between all threads
        static void Main() {
            new Thread(Go).Start();
            Go();
        }
        static void Go() {
            if (!done) {
                done = true;
                Console.WriteLine("Done");
            }
        }
    }

    二、Join & Sleep

    1. Join 等待该线程执行完成之后。
    2. Sleep 暂停当前线程一段时间,Sleep(0) & Yield 同效,将当前进程置为等待状态,让出 CPU 给其他线程。

    三、传递参数

    1. 匿名函数
      Thread t = new Thread ( () => Print ("Hello from t!") );
      
      new Thread (() => {...}).Start();
      
      new Thread (delegate(){...}).Start();
    2. Start 函数
      Thread t = new Thread (Print).Start ("Hello from t!");
      
      static void Print (object messageObj) //函数入参只能为 object 类型
    3. 注意参数的变化
      for (int i = 0; i < 10; i++) new Thread (() => Console.Write (i)).Start();
      
      Output: 0223557799

    四、线程命名

    1. 命名当前线程
      Thread.CurrentThread.Name = "main";
    2. 命名其他线程
      Thread worker = new Thread (Go);
      worker.Name = "worker";

    五、前台线程和后台线程 (Foreground Threads & Background Threads)

    1. 前台线程可以阻止程序退出。除非所有前台线程都结束,否则 CLR不会关闭程序。(自己创建的线程默认前台)
    2. 后台线程有时候也叫 Daemon Thread 。他被 CLR 认为是不重要的执行路径,可以在任何时候舍弃。因此当所有的前台线程结束,即使还有后台线程在执行, CLR 也会关闭程序。(线程池中的线程默认后台)

    线程的前后台与线程的优先级无关。

    某些时候需要等待后台线程执行完成之后退出程序,如释放资源,可如下方式实现:

    1. 如果线程是自己创建的,可以使用 Join 函数
    2. 如果线程是线程池中的,可以使用 Wait 事件

    六、线程优先级

    线程的优先级如下:
    enum ThreadPriority { Lowest, BelowNormal, Normal, AboveNormal, Highest } 

    提升线程的优先级需要仔细认真的考虑,因为可能造成资源的死锁。

    线程的优先级是在进程的优先级之下的,如果A进程中的A1线程想与B进程中B1线程争夺资源,首先应提高A进程的优先级:

    using (Process p = Process.GetCurrentProcess())
    p.PriorityClass = ProcessPriorityClass.High; 

    ProcessPriorityClass.High为进程的最高等级,如果你的进程设置为 High,并且进入了无限循环,操作系统将会被锁定。由于这个原因,High 一般用于实时系统 Realtime,改进程在进入时间轮片之后,将不会出让 CPU 给任何进程。

    七、异常处理

    异常处理try/catch/finally需要写在函数内部,否则会导致主程序的崩溃,程序直接退出。

    八、线程池

    通过Tread创建线程需要消耗时间来组织资源创建线程,并且会消耗内存。使用线程池的线程不会有这些问题。进入线程池方式:

    1. Task Parallel Library(TPL .NET4.0+)
    2. 调用 ThreadPool.QueueUserWorkItem
    3. 异步委托(Asynchronous delegates)
    4. 通过BackgroundWorker

    下列间接使用线程池构建:

    1. WCF、Remoting、ASP.NET、ASMX Web Service 服务
    2. System.Timers.Timer & System.Threading.Timer
    3. 框架方法,如WebClient、大部分的BeginXXX等异步方法
    4. PLINQ

    使用线程池需注意:

    1. 线程池中的线程不可命名,调试困难
    2. 线程池中的线程均为后台线程
    3. 在应用程序生命周期的早期,阻塞线程可能会导致额外的延迟。

    查询当前线程是否在线程池中:Thread.CurrentThread.IsThreadPoolThread.

    九、使用线程池

    1. Task Parallel Library(TPL .NET4.0+)
      Task.Factory.StartNew (Go, arg1, arg2…);

      Go的参数可以不为object类型

      接收返回参数Task<TResult>:

      Task<string> task = Task.Factory.StartNew<string>(() => DownloadString ("http://www.linqpad.net"));
      
      string result = task.Result; //use the result, block the main thread until the task finished 

      当使用返回参数时,相当于在调用参数之前调用了 task.Wait();

    2. 调用 ThreadPool.QueueUserWorkItem

      当使用.NET为4.0之前版本时,我们只能使用ThreadPool.QueueUserWorkItem和Asynchronous delegates两种方式。

    3. 异步委托(Asynchronous delegates)

      与ThreadPool.QueueUserWorkItem区别是:Asynchronous delegates可以接收返回结果,并且可以在主线程中统一处理异常。

      1. 实例化委托
      2. 调用委托的BeginInvoke,使用IAsyncResult接收返回值
      3. 需要使用返回结果时,调用委托的EndInvoke,并且传递已保存的IAsyncResult对象。

      EndInvoke做的三件事:

      1. 等待异步委托执行完成。
      2. 接收返回结果(包括ref & out 参数)
      3. 抛出异常到主线程。

      拆分实现:

      method在BeginInvoke时传递,通过IAsyncResult.AsyncState传递。其中IAsyncResult.AsyncState为object类型,可以传递任何变量。

  • 相关阅读:
    redis持久化的几种方式
    Spring Cloud基础教程
    微服务实践三: 服务编排
    分库分表的几种常见玩法及如何解决跨库查询等问题
    Spring Cloud微服务开发笔记5——Ribbon负载均衡策略规则定制
    第1章 Python基础-Python介绍&循环语句 练习题&作业
    MySQL中 optimize table '表名'的作用
    Python3 命令行参数
    Python enumerate() 函数
    Python rpartition() 方法
  • 原文地址:https://www.cnblogs.com/zhuhc/p/4329122.html
Copyright © 2011-2022 走看看