多线程基础-C#

Posted 全栈黑科技

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程基础-C#相关的知识,希望对你有一定的参考价值。

多线程

  • 线程 被定义为程序的执行流。每个线程都定义了一个单独的控制流。如果应用程序涉及到复杂的和耗时的操作,那么将程序分成多个线程执行流往往是有益的,每个线程执行特定的工作。

  • 线程是轻量级进程。一个使用线程的常见实例是现代操作系统中并行编程的实现。使用线程节省了 CPU 周期的浪费,同时提高了应用程序的效率。

  • 为了同时执行多个任务,一个程序可以被划分为更小的线程。

线程生命周期

线程生命周期开始于 System.Threading.Thread 类的对象被创建时,结束于线程被终止或完成执行时。

  • 未启动状态:当线程实例被创建但 Start方法未被调用时的状况。

  • 就绪状态:当调用了 Start,线程准备好运行并等待 CPU 周期时的状况。

  • 不可运行状态:下面的几种情况下线程是不可运行的:

  • 已经调用 Sleep 方法

  • 已经调用 Wait 方法

  • 通过 I/O 操作阻塞

  • 死亡状态:当线程已完成执行或已中止时的状况。

主线程

  • 在 C# 中,System.Threading.Thread 类用于线程的工作。它允许创建并访问多线程应用程序中的单个线程。进程中第一个被执行的线程称为主线程。

  • 当 C# 程序开始执行时,主线程自动创建。使用 Thread 类创建的线程被主线程的子线程调用。您可以使用 Thread 类的 CurrentThread 属性访问线程。

创建线程

构造函数

 
   
   
 
  1. #ThreadStart:

  2. #public delegate void ThreadStart();//一个无参数,无返回值的委托


  3. #ParameterizedThreadStart:

  4. #public delegate void ParameterizedThreadStart(object obj);//一个有一个参数、但无返回值的委托


  5. #maxStackSize:线程要使用的最大堆栈大小(以字节为单位);如果为 0 则使用可执行文件的文件头中指定的默认最大堆栈大小。 重要地,对于部分受信任的代码,如果 maxStackSize 大于默认堆栈大小,则将其忽略。 不引发异常。

  6. public Thread(ThreadStart start);

  7. public Thread(ParameterizedThreadStart start);

  8. public Thread(ThreadStart start, int maxStackSize);

  9. public Thread(ParameterizedThreadStart start, int maxStackSize);

新建线程

 
   
   
 
  1. public static void CallToChildThread()

  2. {

  3.   Console.WriteLine("Child thread starts");

  4. }


  5. ThreadStart childref = new ThreadStart(CallToChildThread);

  6. Thread childThread = new Thread(childref);

  7. childThread.Start();

调用 Start之后,一个线程就进入了 就绪状态了,等着CPU分配时间片即可。

以上,就是C#的多线程基本知识,如果你只是需要偶尔在程序中使用以下多线程,那么上面的知识就够你启动一个子线程,并将想要执行的任务放到子线程中执行了。

但如果你在线程中大量使用多线程,那么就可能遇到诸如: 线程同步死锁控制线程状态等需求。


前后线程&后台线程

 
   
   
 
  1. #获取或设置一个值,该值指示某个线程是否为后台线程。

  2. public bool IsBackground { get; set; }

.Net的公用语言运行时(Common Language Runtime,CLR)能区分两种不同类型的线程:前台线程和后台线程。 这两者的区别就是:

  • 应用程序必须运行完所有的前台线程才可以退出;

  • 对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。

.NET环境使用Thread建立的线程默认情况下是前台线程,即线程属性IsBackground=false,在进程中,只要有一个前台线程未退出,进程就不会终止。主线程就是一个前台线程。而后台线程不管线程是否结束,只要所有的前台线程都退出(包括正常退出和异常退出)后,进程就会自动终止。

一般后台线程用于处理时间较短的任务,如在一个Web服务器中可以利用后台线程来处理客户端发过来的请求信息。而前台线程一般用于处理需要长时间等待的任务,如在Web服务器中的监听客户端请求的程序,或是定时对某些系统资源进行扫描的程序。

  • 应用程序的主线程以及使用Thread构造的线程都默认为前台线程

  • 线程池线程也就是使用 ThreadPool.QueueUserWorkItem()和Task工厂创建的线程都默认为后台线程

线程执行状态(IsAlive)

 
   
   
 
  1. #获取一个值,该值指示当前线程的执行状态。

  2. #如果此线程已启动并且尚未正常终止或中止,则为 true;否则为 false。

  3. public bool IsAlive { get; }

线程状态(ThreadState)

 
   
   
 
  1. #获取一个值,该值包含当前线程的状态

  2. #System.Threading.ThreadState 值之一(Running、StopRequested、SuspendRequested、Background、Unstarted、Stopped、WaitSleepJoin、Suspended、AbortRequested、Aborted),它指示当前线程的状态。 初始值为 Unstarted。

  3. public ThreadState ThreadState { get; }

线程归属(IsThreadPoolThread)

 
   
   
 
  1. #获取一个值,该值指示线程是否属于托管线程池。

  2. #如果此线程属于托管线程池,则为 true;否则为 false。

  3. public bool IsThreadPoolThread { get; }

线程标识符(ManagedThreadId)

 
   
   
 
  1. #获取当前托管线程的唯一标识符。

  2. #一个整数,表示此托管线程的唯一标识符。

  3. public int ManagedThreadId { get; }

线程名字(Name)

 
   
   
 
  1. #获取或设置线程的名称。

  2. #包含线程名称的字符串,或者如果未设置名称,则为 null。

  3. public string Name { get; set; }

线程优先级(Priority)

 
   
   
 
  1. #获取或设置一个值,该值指示线程的调度优先级。

  2. #System.Threading.ThreadPriority(Lowest、BelowNormal、Normal、AboveNormal、Highest) 值之一。 默认值为 Normal。

  3. public ThreadPriority Priority { get; set; }

立即执行当前线程,同时阻塞其余线程

 
   
   
 
  1. #在继续执行标准的 COM 和 SendMessage 消息泵处理期间,阻塞调用线程,直到某个线程终止或经过了指定时间为止。

  2. #如果线程已终止,则为 true;如果线程在经过了 millisecondsTimeout 参数指定的时间量后未终止,则为 false。

  3. public void Join();

  4. public bool Join(int millisecondsTimeout);

  5. public bool Join(TimeSpan timeout);

这个方法可以使当前线程立即执行,如果没有参数,则会一直等到当前线程执行结束,如果有参数,则当过时间之后,就会取消这种超级优先级状态。

挂起线程与继续挂起线程

 
   
   
 
  1. #挂起线程,或者如果线程已挂起,则不起作用。

  2. public void Suspend();

 
   
   
 
  1. #继续已挂起的线程。

  2. public void Resume();

线程休眠(sleep)

 
   
   
 
  1. #timeout:设置为线程被阻塞的时间量的 System.TimeSpan。 指定零以指示应挂起此线程以使其他等待线程能够执行。 指定 System.Threading.Timeout.Infinite以无限期阻止线程。

  2. public static void Sleep(TimeSpan timeout);


  3. #线程被阻塞的毫秒数。 指定零 (0) 以指示应挂起此线程以使其他等待线程能够执行。 指定 System.Threading.Timeout.Infinite以无限期阻止线程。

  4. public static void Sleep(int millisecondsTimeout);

 
   
   
 
  1. #当前线程暂停 5000 毫秒

  2. int sleepfor = 5000;

  3. Thread.Sleep(sleepfor);

销毁线程(Abort)

  • Abort() 方法用于销毁线程。

  • 通过抛出 threadabortexception 在运行时中止线程。这个异常不能被捕获,如果有 finally 块,控制会被送至 finally 块。

 
   
   
 
  1. #在调用此方法的线程上引发 System.Threading.ThreadAbortException,以开始终止此线程的过程。 调用此方法通常会终止线程。

  2. public void Abort(object stateInfo);

  3. public void Abort();

 
   
   
 
  1. public static void CallToChildThread()

  2. {

  3.     try{

  4.           Console.WriteLine("Child thread starts");

  5.           // 计数到 10

  6.           for (int counter = 0; counter <= 10; counter++)

  7.           {

  8.               Thread.Sleep(500);

  9.               Console.WriteLine(counter);

  10.           }

  11.           Console.WriteLine("Child Thread Completed");

  12.       }

  13.       catch (ThreadAbortException e)

  14.       {

  15.           Console.WriteLine("Thread Abort Exception");

  16.       }

  17.       finally

  18.       {

  19.           Console.WriteLine("Couldn't catch the Thread Exception");

  20.       }

  21. }


  22. static void Main(string[] args)

  23. {

  24.    ThreadStart childref = new ThreadStart(CallToChildThread);

  25.    Console.WriteLine("In Main: Creating the Child thread");

  26.    Thread childThread = new Thread(childref);

  27.    childThread.Start();

  28.    // 停止主线程一段时间

  29.    Thread.Sleep(2000);

  30.    // 现在中止子线程

  31.    Console.WriteLine("In Main: Aborting the Child thread");

  32.    childThread.Abort();

  33.    Console.ReadKey();    

  34. }

当上面的代码被编译和执行时,它会产生下列结果:

 
   
   
 
  1. In Main: Creating the Child thread

  2. Child thread starts

  3. 0

  4. 1

  5. 2

  6. In Main: Aborting the Child thread

  7. Thread Abort Exception

  8. Couldn't catch the Thread Exceptio


以上是关于多线程基础-C#的主要内容,如果未能解决你的问题,请参考以下文章

C++11多线程 原子操作概念及范例

基础数据类型多线程是否需要加锁

20160226.CCPP体系详解(0036天)

多个用户访问同一段代码

javaAPI_多线程基础_多线程基础1

线程学习知识点总结