• C# 多线程编程


    1.如果只是启动一个新线程,不需要传入参数,不需要线程返回结果,可以直接使用ThreadStart(),

    Thread类接收一个ThreadStart委托或ParameterizedThreadStart委托的构造函数。ThreadStart委托中  作为参数的方法   不需要参数,并且没有返回值。ParameterizedThreadStart委托,可以在线程start的时候,传入参数,利用这个参数可以向线程传递参数(ParameterizedThreadStart是一个有参的、返回值为void的委托,参数类型必须是object)。

    private void btOnlineLogin_Click(object sender, EventArgs e) 
        {
            Thread CheckStatusThread = new Thread(new ThreadStart(CheckStatus));       
         CheckStatusThread.Start(); //无参和返回值的多线程 
      }

    private void CheckStatus()
    {
      //do some thing here
    }

    2. 如果需要向线程传入参数,但不需要线程返回值,用ParameterizedThreadStart是一个有参的、返回值为void的委托,参数类型必须是object,且只能有一个object参数传入,
    如果要传入多个参数,可以用下面3中的Func()或者定义一个结构体,结构体包含你要传入的参数,然后把结构体当作object传入。

    private void btOnlineLogin_Click(object sender, EventArgs e) 
    {
            Thread CheckStatusThread = new Thread(new ParameterizedThreadStart(CheckStatus));       
        CheckStatusThread.Start("print me"); //有传入参,无返回值的多线程 
    }

    private void CheckStatus(object value)
    {
      Console.WriteLine(value)
    }
    //==============================总之上述用Thread方式,都没有返回值。

    3.如果新线程不需要传入参数,但是需要得到返回结果,可以有两种做法:

    a: 定义一个全局变量,按照上述1中方法启动一个无参无函数返回值的线程,将要返回的结果设置给全局变量

      public class Class1
      {
        bool Ready= false;
        private void btOnlineLogin_Click(object sender, EventArgs e)
        {
          Thread CheckStatusThread = new Thread(new ThreadStart(CheckStatus));
          CheckStatusThread.Start(); //无参和返回值的多线程

          while(!Ready)
          {
            Console.WriteLine("wait for status to ready");
          }

        }

        private void CheckStationLockedWindow()
        {
          System.Threading.Thread.Sleep(1000); //使 UI 线程有了处理界面消息的机会
          Ready = true;
        }

      }

    b.使用Func(in_param_type, in_param_type, out_param_type), 然后使用Func的BeginInvoke() 异步启动一个新线程,该做法界面会卡住。

    private void button33_Click(object sender, EventArgs e)
    {
      Func<bool> test = MyTestMethod;
      // Func<bool> test = new Func<bool>(MyTestMethod); //这样一样
      IAsyncResult result = test.BeginInvoke(null, null); //不用传入参数
      bool fin = test.EndInvoke(result);
      if(fin)
      {
        Console.WriteLine("OK.........");
      }

    }

    private bool WaitAndCreateEmptyFwFolder()
    {
      Stopwatch timer = new Stopwatch();
      timer.Reset();
      timer.Start();
      while(timer.ElapsedMilliseconds <20*1000)
      {

        System.Threading.Thread.Sleep(1000); //使 UI 线程有处理界面消息的机会,防止卡住

        Application.DoEvents();

        Console.WriteLine("Elappsed time:" + timer.ElapsedMilliseconds.ToString());
      }
      return true;
    }

    3. 如果即需要给线程传入参数还需要得到线程返回值,还是可以用Func(), 用Func() 可以不用定义自己的delegate了。

    public class Class1
    { 
       private void button33_Click(object sender, EventArgs e)
      {
        Func<string, bool> test = PrintSomeThing;
        IAsyncResult result = test.BeginInvoke("Print me", null, null);
        bool fin = test.EndInvoke(result);

    if (fin)
    {
    Console.WriteLine("OK.........");
    }

      }

      private bool PrintSomeThing(string arg)

      {

    Stopwatch timer = new Stopwatch();
    timer.Reset();
    timer.Start();
    while (timer.ElapsedMilliseconds < 10 * 1000)
    {

      System.Threading.Thread.Sleep(1000); //使 UI 线程有处理界面消息的机会

        Application.DoEvents();
        Console.WriteLine(arg);
      }
    return true;

    }

    }

    4. 第四种多线程用task:System.Thread.Tasks.Task

    Task的参数有两种,一种是Action(无返回值),一种是Func。

    public class Class1

    {

       private void button33_Click(object sender, EventArgs e)

         {

    //==============带有返回值和传入参数的
    //Task task  = Task<bool>.Factory.StartNew(new Func<object,bool>(TaskMthod),"321");   //带有返回值和传入参数的
    Task<bool> task = new Task<bool>(TaskMthodWithReturnAndInParam, "123");   //new Task<>()中的<>里面放返回值类型,
                                         //()里面放Func类型method名字。
                                         // 如果直接用new Task()没有<>则没有返回值,里面放Action类型method名字。

    task.Start();//start async          

    //Console.WriteLine(task.Result.ToString()); //task.Result will block the thread unitil the task is done and run to next step, UI will stuck
    //task.Wait(); //will block until done
        while(!task.IsCompleted) // this won't block UI
              {
                    Application.DoEvents();
              }
              Console.WriteLine(task.Result.ToString());
    //================只有返回值,无传入参数的
    Task<bool> task2 = new Task<bool>(TaskMthodWithReturnNoInParam);          
    task2.Start();//start async
       while(!task2.IsCompleted)
              {
                    Application.DoEvents();
              }
    Console.WriteLine(task2.Result.ToString());
    
    //Task.WaitAll(task1,task2); //wait all task done

    //===================没有返回值,只有传入参数的
    Task task = Task.Run(() => TaskMthodWithInParamOnly(true, true));          
    while (!task.IsCompleted)          
    {              
    Application.DoEvents();          
    }

    }
    private void TaskMthodWithInParamOnly(bool val1, bool val2)
    {
        Stopwatch timer = new Stopwatch();
        timer.Reset();
        timer.Start();
        while (timer.ElapsedMilliseconds < 20 * 1000)
        {
            Console.WriteLine("Elappsed time:" + timer.ElapsedMilliseconds.ToString());
        }
    }
    private bool TaskMthodWithReturnNoInParam()
    {
          Stopwatch timer = new Stopwatch();
          timer.Reset();
          timer.Start();
          while (timer.ElapsedMilliseconds < 20 * 1000)
          {
              Console.WriteLine("Elappsed time:" + timer.ElapsedMilliseconds.ToString());
          }
          return true;
    }
     
    private bool TaskMthodWithReturnAndInParam(object val)
    {
          Stopwatch timer = new Stopwatch();
          timer.Reset();
          timer.Start();
          while (timer.ElapsedMilliseconds < 20 * 1000)
          {
              Console.WriteLine(val.ToString());
          }
          return true;
    }
    }

    如下内容引自https://www.cnblogs.com/liuqiyun/p/8110058.html

    BeginInvoke 方法所调用的委托无论如何都是在 UI 线程中执行的。
    那 BeginInvoke 究竟有什么用呢?
    在多线程编程中,我们经常要在工作线程中去更新界面显示,而在多线程中直接调用界面控件的方法是错误的做法,具体的原因可以在看完我的这篇之后看看这篇:在多线程中如何调用Winform,如果你是大牛的话就不要看我这篇了,直接看那篇吧,反正那篇文章我没怎么看懂。
    Invoke 和 BeginInvoke 就是为了解决这个问题而出现的,使你在多线程中安全的更新界面显示。
    正确的做法是将工作线程中涉及更新界面的代码封装为一个方法,通过 Invoke 或者 BeginInvoke 去调用,两者的区别就是一个导致工作线程等待,而另外一个则不会。
    而所谓的“一面响应操作,一面添加节点”永远只能是相对的,使 UI 线程的负担不至于太大而以,因为界面的正确更新始终要通过 UI 线程去做,我们要做的事情是在工作线程中包揽大部分的运算,而将对纯粹的界面更新放到 UI 线程中去做,这样也就达到了减轻 UI 线程负担的目的了。

  • 相关阅读:
    【spring源码分析】IOC容器初始化(五)
    【spring源码分析】IOC容器初始化(四)
    【spring源码分析】IOC容器初始化(三)
    【spring源码分析】IOC容器初始化(二)
    Thread.currentThread()和this的区别——《Java多线程编程核心技术》
    【spring源码分析】IOC容器初始化(一)
    【spring源码分析】准备工作
    DefaultNamespaceHandlerResolver中handlerMappings如何初始化
    SimpleDateFormat非线程安全
    MyBatis批量操作
  • 原文地址:https://www.cnblogs.com/keeprealblog/p/12804038.html
Copyright © 2020-2023  润新知