服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C#中Thread(线程)和Task(任务)实例详解

C#中Thread(线程)和Task(任务)实例详解

2023-02-22 16:34唯有自己强大 C#

.NET Framework在System.Threading命名空间中具有与线程相关的类,线程是一小组可执行指令,这篇文章主要给大家介绍了关于C#中Thread(线程)和Task(任务)的相关资料,需要的朋友可以参考下

线程

线程:对于所有需要等待的操作,例如移动文件,数据库和网络访问都需要一定的时间,此时就可以启动一个新的线程,同时完成其他任务。一个进程的多个线程可以同时运行在不同的CPU上或多核CPU的不同内核上。

一个应用程序启动时,会启动一个进程(应用程序的载体),然后进程会启动多个线程。

一,使用Thread类启动线程和数据传输

使用Thread类可以创建和控制线程,Thread构造函数是一个无参无返回值的委托类型。

1️⃣对Thread传入一个无参无返回类型的方法-ThreadStart。

    public delegate void ThreadStart();

实例:

        static  void test()
      {
          Console.WriteLine("test is start");
          Console.WriteLine("test is running");
          Thread.Sleep(3000);
          Console.WriteLine("test is completed");
      }

      static void Main(string[] args)
      {
          Thread th = new Thread(test);
          th.Start();
          Console.WriteLine("main is completed");
      }

C#中Thread(线程)和Task(任务)实例详解

2️⃣对Thread传入一个匿名方法(或lambda表达式)。用于传入的方法代码简单的情况

        static void Main(string[] args)
      {
          //lambad表达式
          Thread th = new Thread(()=> {
              Console.WriteLine("子线程1-ID:" + Thread.CurrentThread.ManagedThreadId);
          });
          th.Start();
          //匿名方法
          Thread th2 = new Thread(delegate ()
          {
              Console.WriteLine("子线程2-ID:" + Thread.CurrentThread.ManagedThreadId);
          });
          th2.Start();
          Console.WriteLine("main is completed");
      }

C#中Thread(线程)和Task(任务)实例详解

3️⃣对Thread传入一个无返回值有参方法-ParameterizedThreadStart,该参数只能是object类型且只能有一个参数。

    public delegate void ParameterizedThreadStart(object? obj);

实例:

        static void download(object o)
      {
          string str = o as string;
          Console.WriteLine("地址:" + str);
      }
      static void Main(string[] args)
      {
          Thread th = new Thread(download);
          th.Start("http://baidu.com");
          Console.WriteLine("main is completed");
      }

C#中Thread(线程)和Task(任务)实例详解

注意:使用as进行强制类型转换 成功会正确输出,失败会输出null。

以上数据传输的方法都是基于静态变量进行传输的,但是定义过多静态变量会导致多个线程访问同一个静态变量,造成资源冲突。

静态变量虽然方便访问,但是静态的一般都是公共的,容易混乱。

4️⃣对Thread传入一个无返回值多个参数的方法(定义一个结构体),但是不能用as强制转换。

        public struct data
      {
          public string message;
          public int age;
      }
      static void download(object o)
      {
          data str = (data)o;//强制类型转换
          Console.WriteLine("信息:" + str.message);
          Console.WriteLine("年纪:" + str.age);
      }
      static void Main(string[] args)
      {
          data da = new data();
          da.message = "sss";
          da.age = 3;
          Thread th = new Thread(download);
          th.Start(da);
          Console.WriteLine("main is completed");
      }

由于结构体是值类型,不能为null,因此不能用as进行强制类型转换。

5️⃣通过自定义类传递数据(即将通过线程调用一个类的成员方法)

先创建一个download类:

    class downLoad
  {
      public string URL { get; private set; }
      public string Message { get; private set; }
      //构造函数
      public downLoad(string uRL, string message)
      {
          URL = uRL;
          Message = message;
      }
      //下载方法
      public void  load()
      {
          Console.WriteLine("从" + URL + "获取信息:" + Message);
      }
  }

在主程序中将该类的成员方法传入Thread中:

   static void Main(string[] args)
      {
          var download = new downLoad("www.baidu.com", "mp4");
          Thread th = new Thread(download.load);
          th.Start();
          Console.WriteLine("main is completed");
          Console.ReadKey();
      }

知识点拓展1-前台线程与后台线程:

应用程序的进程需要等待所有前台线程完成其任务后才会结束。而后台线程在应用程序关闭后会自动关闭,即使后台线程还没有执行完毕。在默认情况下,用Thread类创建的线程是前台线程,线程池中的线程是后台线程。在Thread类创建线程的时候,可以设置IsBackground属性,表示它是否是一个后台线程。

知识点拓展2-线程的优先级

线程有操作系统调度,一个CPU同一时间只能做一件事(运行一个线程中的计算任务),当有很多线程需要CPU执行时,线程调度器会根据线程的优先级去判断先去执行哪个线程,如果优先级相同,就使用一个循环调度规则,逐个执行每个线程。

在Thread类中,可以设置Priority属性,以影响线程的基本优先级,Priority属性一个ThreadPriority枚举定义的一个值,定义级别有Highest,AboveNormal,Normal,BelowNormal,和Lowest。

因此对于重要的线程任务,可以将线程优先级设置高一点,使其可以尽快执行完毕。

如果需要等待线程执行结果在执行后面的代码,可以调用Thread对象的join方法,即将该线程加入进来,并停止当前线程,直至加入的线程执行完毕。

二,线程池ThreadPool类

由于线程的创建需要时间,如果有不同的小任务要完成,就可以事先创建多个线程。系统有一个ThreadPool类来管理线程,这个类会在需要线程的时候增加线程数,不需要时候减少。池中最大线程数是可配置的。在双核CPU中,默认设置为1023个工作线程和1000个IO线程,如果需要更多线程(超过了线程池的最大数量),最新的任务就需要排队等待。

使用线程池,即调用ThreadPool.QueueUserWorkItem方法,该方法需要传入一个WaitCallBack类型的委托(即传入带一个object参数的方法)。然后ThreadPool会在池中找一个空闲的线程去执行传入的方法。

        static void Main(string[] args)
      {
          for (int i = 0; i < 10; i++)
          {
              ThreadPool.QueueUserWorkItem(work);              
          }
          Thread.Sleep(10000);
      }
      static void work(object state)
      {
          Console.WriteLine("线程id" + Thread.CurrentThread.ManagedThreadId);
      }

C#中Thread(线程)和Task(任务)实例详解

需要注意的是:

线程池中所有线程都是后台线程,如果进程中所有的前台线程都结束了,所有的后台线程也会跟着结束。不能把入池的后台线程改为前台线程。不能给入池的线程设置优先级或名称。入池的线程只能是用于时间较短的任务。如果线程要一直运行,就应用Thread类创建一个线程。

 

任务

任务表示应完成某个单元的工作,这个工作可以在单独的线程中运行,也可以同步方式启动一个任务。任务在后台使用ThreadPool进行管理的,也就是说任务启动的也是后台线程。

一,创建并启动任务

启动任务的两种方式:

        static void Main(string[] args)
      {
          //第一种:使用TaskFactory
          TaskFactory tf = new TaskFactory();
          tf.StartNew(work);
          //第二种:使用Task
          Task t = new Task(work);
          t.Start();
          Console.WriteLine("main is completed");
      }
      static void work()
      {
          Console.WriteLine("线程id" + Thread.CurrentThread.ManagedThreadId);
      }

C#中Thread(线程)和Task(任务)实例详解

需要注意的是:使用TaskFactory创建任务,传入的方法为无参的。

二,连续任务

如果一个任务t1的执行是依赖于另一个任务t2,那么就需要在t2执行完毕后才开始执行t1。(例如:迅雷下载完成后弹出界面提示)这时候我们可以使用连续任务ContinueWith。

        static void Main(string[] args)
      {
          Task t1 = new Task(download);
          Task t2 = t1.ContinueWith(show);
          t1.Start();
          Thread.Sleep(2000);
      }
      static void download()
      {
          Console.WriteLine("正在下载中。。。。");
          Thread.Sleep(1000);
      }
      static void show(Task t)
      {
          Console.WriteLine("下载完成!");
      }

C#中Thread(线程)和Task(任务)实例详解

需要注意的是:传入t2的方法的参数需为Task类型。

三,资源冲突问题

在多线程中如果多个线程同时访问同一资源,就会产生资源冲突的问题。这时候需要用lock对程序进行加锁。

什么是资源冲突?

    class state
  {
      public int num = 5;
      public void checknum()
      {
          if (num==5)
          {
              num++;
              Console.WriteLine("num的值:" + num + "当前线程id:" + Thread.CurrentThread.ManagedThreadId); 
          }
          num =5;
      }
  }
  static void Main(string[] args)
      {
          state st = new state();
          for (int i = 0; i < 10; i++)
          {
              Thread th = new Thread(st.checknum);
              th.Start();
          }
      }

在主程序使用多线程调用state类的check方法,可以看到num=5和num=6造成资源冲突了。

C#中Thread(线程)和Task(任务)实例详解

对多个线程访问的对象进行加锁

        object _lock = new object();
      public int num = 5;
      public void checknum()
      {
          lock(_lock)
          {
          if (num==5)
          {
              num++;
              Console.WriteLine("num的值:" + num + "当前线程id:" + Thread.CurrentThread.ManagedThreadId); 
          }
          num =5;
          }
      }

C#中Thread(线程)和Task(任务)实例详解

 

总结

到此这篇关于C#中Thread(线程)和Task(任务)的文章就介绍到这了,更多相关C# 线程和任务内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/xyf327/p/16010782.html

延伸 · 阅读

精彩推荐
  • C#C# Console.WriteLine()用法案例详解

    C# Console.WriteLine()用法案例详解

    这篇文章主要介绍了C# Console.WriteLine()用法案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...

    七喜不加冰7672022-11-30
  • C#C#中如何在Excel工作表创建混合型图表实例

    C#中如何在Excel工作表创建混合型图表实例

    本篇文章主要介绍了C#中如何在Excel工作表创建混合型图表实例,具有一定的参考价值,有需要的可以了解一下。...

    Yesi6092021-12-10
  • C#C# 通过同步和异步实现优化做早餐的时间

    C# 通过同步和异步实现优化做早餐的时间

    本文以一个简单的小例子—如何做一顿早餐及如何优化做早餐的时间来让大家具体了解一下同步和异步方法的区别,需要的朋友可以参考一下...

    Alan.hsiang6202022-12-12
  • C#详解c#中Array,ArrayList与List<T>的区别、共性与相互转换

    详解c#中Array,ArrayList与List<T>的区别、共性与相互转换

    本文详细讲解了c#中Array,ArrayList与List<T>的区别、共性与相互转换,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需...

    sogeisetsu7412022-12-14
  • C#Unity调用打印机打印图片

    Unity调用打印机打印图片

    这篇文章主要为大家详细介绍了Unity通过调用打印机打印图片的代码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一...

    月夜风雨磊10122022-08-08
  • C#解析错误富文本json字符串(带双引号)的快速解决方法

    解析错误富文本json字符串(带双引号)的快速解决方法

    下面小编就为大家带来一篇解析错误富文本json字符串(带双引号)的快速解决方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小...

    C#教程网5582021-12-02
  • C#C# lambda表达式原理定义及实例详解

    C# lambda表达式原理定义及实例详解

    这篇文章主要介绍了C# lambda表达式原理定义及实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可...

    盗哥泡茶去了4702022-09-26
  • C#C# for循环的经典案例集锦

    C# for循环的经典案例集锦

    本篇文章主要介绍了关于for循环的经典案例,具有很好的参考价值。下面跟着小编一起来看下吧...

    涂涂的世界9992022-01-05