[.Net 线程处理系列]专题一:线程基础

简介:

引言:

    最近一段时间都在研究关于.Net线程的内容,觉得线程是每个程序员都应该掌握的,所以写下这个线程的系列希望能给大家学习过程中一些帮助,同时也是自己对线程的巩固,当中如果有什么错漏还请大家指出,这样我们可以互相得到进步。

目录

一、线程的介绍

二、线程调度和优先级

三、前台线程和后台线程

四、简单线程的使用

五、小结

 

一、线程的介绍

在介绍线程之前, 很有必要知道什么是进程,以及与线程的关系。

     进程(Process)是应用程序的实例要使用的资源的一个集合(从可以简化理解:进程就是一种资源,是应用程序所用的资源)。每个应用程序都在各自的进程中运行来确保应用程序不受其他应用程序的影响,如果一个应用程序失败了, 只会影响自己的进程,其他进程中的应用程序可以继续运行。进程是操作系统为我们提供的一种保护应用程序的一种机制。

     线程是进程中基本执行单元, 一个进程中可以包含多个线程,在进程入口执行的第一个线程是一个进程的主线程,在.Net应用程序中,都是以Main()方法作为程序的入口的, 所以在程序运行过程中调用这个方法时,系统就会自动创建一个主线程。(他们之间的关系简单说:线程是进程的执行单元,进程是线程的一个容器了)。

二、线程调度和优先级

    Windows之所以被称为抢占式多线程操作系统,是因为线程可以在任意时间被抢占,并调度另一个线程。每个线程都分配了从0~31的一个优先级。系统首先把高优先级的线程分配给CPU执行。Windows 支持7个相对线程优先级:Idle,Lowest,Below Normal,Normal,Above Normal,Highest和Time-Critical,Normal是默认的线程优先级,然而在程序中可以通过设置Thread的Priority属性来改变线程的优先级,它的类型为ThreadPriority枚举类型,包含枚举有:Lowest,BelowNormal,Normal,AboveNormal和Highest,CLR为自己保留了 Idle和Time-Critical优先级。具体每个枚举值含义如下表

成员名称 说明
Lowest 可以将 Thread何其他优先级的线程之后。
BelowNormal 可以将 Thread Normal 优先级的线程之后,在具有 Lowest 优先级的线程之前。
Normal

可以将 Thread AboveNormal 优先级的线程之后,在具有 BelowNormal 优先级的线程之前。

默认情况下,线程具有 Normal 优先级。

AboveNormal 可以将 Thread Highest 优先级的线程之后,在具有 Normal 优先级的线程之前。
Highest 可以将 Thread 其他优先级的线程之前。

 

 

 

 

 

 

三、前台线程和后台线程

     在.net中线程分为前台线程和后台线程,在一个进程中,当所有前台线程停止运行时,CLR会强制结束仍在运行的任何后台线程,这些后台线程直接被终止,不会抛出异常。

     所以我们应该在前台线程中执行我们确实要完成的事情,另外, 应该把非关键的任务使用后台线程,我们用Thread创建的是线程为前台线程。让我们通过下面的一段代码来看看前台线程和后台线成的区别:


 
 
  1. using System;  
  2. using System.Threading;  
  3.  
  4.  class Program  
  5.     {  
  6.         static void Main(string[] args)  
  7.         {  
  8.         // 创建一个新线程(默认为前台线程)  
  9.             Thread backthread = new Thread(Worker);  
  10.  
  11.             // 使线程成为一个后台线程  
  12.             backthread.IsBackground = true;  
  13.  
  14.             // 通过Start方法启动线程  
  15.             backthread.Start();  
  16.  
  17.             // 如果backthread是前台线程,则应用程序大约5秒后才终止  
  18.             // 如果backthread是后台线程,则应用程序立即终止  
  19.             Console.WriteLine("Return from Main Thread");  
  20.         }  
  21.         private static void Worker()  
  22.         {  
  23.             // 模拟做10秒  
  24.             Thread.Sleep(5000);  
  25.  
  26.             // 下面语句,只有由一个前台线程执行时,才会显示出来  
  27.             Console.WriteLine("Return from Worker Thread");  
  28.         }  

    运行上面代码可以发现:控制台中显示字符串: Return form Main Thread 后就退出了, 字符串 Return from Worker Thread字符串根本就没有显示,这是因为此时的backthread线程为后台线程,当主线程(执行Main方法的线程,主线程当然也是前台线程了)结束运行后,CLR会强制终止后台线程的运行,整个进程就被销毁了,并不会等待后台线程运行完后才销毁。如果把 backthread.IsBackground = true; 注释掉后, 就可以看到控制台过5秒后就输出 Return from Worker Thread。再在Worker方法最后加一句 代码:Console.Read(); 就可以看到这样的结果了

注意:有些人可能会问我不想把 backthread.IsBackground = true;注释掉, 又想把Worker()方法中的字符串输出在控制台上怎么做呢? 其实是有解决的办法的, 我们可以调用thread.Join()方法来实现,Join()方法能保证主线程(前台线程)在异步线程thread(后台线程)运行结束后才会运行。

实现代码如下:


  
  
  1. using System;  
  2. using System.Threading;  
  3.  class Program  
  4.     {  
  5.         static void Main(string[] args)  
  6.         {  
  7.  // 创建一个新线程(默认为前台线程)  
  8.             Thread backthread = new Thread(Worker);  
  9.  
  10.             // 使线程成为一个后台线程  
  11.             backthread.IsBackground = true;  
  12.  
  13.             // 通过Start方法启动线程  
  14.             backthread.Start();  
  15.             backthread.Join();  
  16.  
  17.             // 模拟主线程的输出  
  18.             Thread.Sleep(2000);  
  19.  
  20.             Console.WriteLine("Return from Main Thread");  
  21.             Console.Read();  
  22.         }  
  23.         private static void Worker()  
  24.         {  
  25.             // 模拟做3秒  
  26.             Thread.Sleep(3000);   
  27.  
  28.             // 下面语句,只有由一个前台线程执行时,才会显示出来  
  29.             Console.WriteLine("Return from Worker Thread");  
  30.         }  

运行结果(调用Join方法后后台线程会阻塞主线程所以主线程会后输出):

四、简单线程的使用

    其实在上面介绍前台线程和后台线程的时候已经通过ThreadStart委托创建了一个线程了,此时已经实现了一个多线程的一个过程,为此系列中将多线程也是做一个铺垫吧。下面通过ParameterizedThreadStart委托的方式来实现多线程。

ParameterizedThreadStart委托的方式来实现多线程:


 
 
  1. using System;  
  2. using System.Threading;  
  3.  class Program  
  4.     {  
  5.         static void Main(string[] args)  
  6.         {  
  7. // 创建一个新线程(默认为前台线程)  
  8.             Thread backthread = new Thread(new ParameterizedThreadStart(Worker));  
  9.  
  10.             
  11.             // 通过Start方法启动线程  
  12.             backthread.Start("123");  
  13.  
  14.             // 如果backthread是前台线程,则应用程序大约5秒后才终止  
  15.             // 如果backthread是后台线程,则应用程序立即终止  
  16.             Console.WriteLine("Return from Main Thread");  
  17.         }  
  18.  
  19.         private static void Worker(object data)  
  20.         {  
  21.             // 模拟做5秒  
  22.             Thread.Sleep(5000);  
  23.  
  24.             // 下面语句,只有由一个前台线程执行时,才会显示出来  
  25.             Console.WriteLine(data + " Return from Worker Thread");  
  26.             Console.Read();  
  27.         }  
 
注意:此时Worker方法传入了一个参数,并且Start方法也传递了一个字符传参数。 对比与之前创建Thread的不同,

运行结果为:

五、小结   

    写到这里, 本系列的第一篇差不多讲完了,在后续的文章将会介绍Thread方法的使用以及通过一些例子来展示他们的不同之处(像Abort()方法Interrupt方法等)对于线程的一些高级使用(如线程池,并行编程和PLINQ、线程同步和计时器)都会在后续中讲到。希望本系列可以给初学线程的人有所帮助。

 




     本文转自LearningHard 51CTO博客,原文链接:http://blog.51cto.com/learninghard/1034787,如需转载请自行联系原作者



相关文章
|
并行计算 安全 Java
C# .NET面试系列四:多线程
<h2>多线程 #### 1. 根据线程安全的相关知识,分析以下代码,当调用 test 方法时 i > 10 时是否会引起死锁? 并简要说明理由。 ```c# public void test(int i) { lock(this) { if (i > 10) { i--; test(i); } } } ``` 在给定的代码中,不会发生死锁。死锁通常是由于两个或多个线程互相等待对方释放锁而无法继续执行的情况。在这个代码中,只有一个线程持有锁,且没有其他线程参与,因此不
769 3
|
10月前
|
开发框架 Java .NET
.net core 非阻塞的异步编程 及 线程调度过程
【11月更文挑战第12天】本文介绍了.NET Core中的非阻塞异步编程,包括其基本概念、实现方式及应用示例。通过`async`和`await`关键字,程序可在等待I/O操作时保持线程不被阻塞,提高性能。文章还详细说明了异步方法的基础示例、线程调度过程、延续任务机制、同步上下文的作用以及如何使用`Task.WhenAll`和`Task.WhenAny`处理多个异步任务的并发执行。
178 1
|
开发框架 监控 Java
【.NET Core】多线程之线程池(ThreadPool)详解(二)
【.NET Core】多线程之线程池(ThreadPool)详解(二)
268 3
|
SQL 开发框架 Java
【.NET Core】多线程之线程池(ThreadPool)详解(一)
【.NET Core】多线程之线程池(ThreadPool)详解(一)
699 2
|
算法 安全 Java
【.NET Core】 多线程之(Thread)详解
【.NET Core】 多线程之(Thread)详解
194 1
|
C# Windows
.NET一个线程更新另一个线程的UI(两种实现方法及若干简化)
原文:.NET一个线程更新另一个线程的UI(两种实现方法及若干简化) 本片博文接上一篇:.NET多线程执行函数,给出实现一个线程更新另一个线程UI的两种方法。 Winform中的控件是绑定到特定的线程的(一般是主线程),这意味着从另一个线程更新主线程的控件不能直接调用该控件的成员。
1689 0
|
数据采集 Java C++
【.NET 6】多线程的几种打开方式和代码演示
多线程无处不在,平常的开发过程中,应该算是最常用的基础技术之一了。以下通过Thread、ThreadPool、再到Task、Parallel、线程锁、线程取消等方面,一步步进行演示多线程的一些基础操作。欢迎大家围观。如果大佬们有其他关于多线程的拓展,也欢迎在评论区进行留言,大佬们的知识互助,是.net生态发展的重要一环,欢迎大佬们进行留言,帮助更多的人。
357 0
【.NET 6】多线程的几种打开方式和代码演示
|
安全 NoSQL MongoDB
.Net线程同步技术解读
C#开发者(面试者)都会遇到lock(Monitor),Mutex,Semaphore,SemaphoreSlim这四个与锁相关的C#类型,本文期望以最简洁明了的方式阐述四种对象的区别。
.Net线程同步技术解读
|
XML 存储 开发框架
ASP.NET多线程的使用(二)
线程,是操作系统中的术语,是操作系统进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。一个进程可以有很多线程,每条线程并行执行不同的任务。同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。我们把用来执行用户任务的线程称为工作线程。而线程池,是一种成熟的线程使用模式。
257 0
ASP.NET多线程的使用(二)
|
存储 开发框架 Java
ASP.NET多线程的使用(一)
线程,是操作系统中的术语,是操作系统进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。一个进程可以有很多线程,每条线程并行执行不同的任务。同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。我们把用来执行用户任务的线程称为工作线程。而线程池,是一种成熟的线程使用模式。
393 0
ASP.NET多线程的使用(一)