进程与线程

1.进程

进程(Process)是Windows系统中的一个基本概念,它包含着一个运行程序所需要的资源。进程之间是相对独立的,一个进程无法访问另一个进程的数据(除非利用分布式计算方式),一个进程运行的失败也不会影响其他进程的运行,Windows系统就是利用进程把工作划分为多个独立的区域的。进程可以理解为一个程序的基本边界。是应用程序的一个运行例程,是应用程序的一次动态执行过程。一个正在运行的应用程序在操作系统中被视为一个进程

2.线程

线程(Thread)是进程中的基本执行单元,是操作系统分配CPU时间的基本单位,一个进程可以包含若干个线程,在进程入口执行的第一个线程被视为这个进程的主线程。在.NET应用程序中,都是以Main()方法作为入口的,当调用此方法时系统就会自动创建一个主线程。线程主要是由CPU寄存器、调用栈和线程本地存储器(Thread Local Storage,TLS)组成的。

(1)CPU寄存器主要记录当前所执行线程的状态,

(2)调用栈主要用于维护线程所调用到的内存与数据,

(3)TLS主要用于存放线程的状态信息。

2.1多线程

2.1.1多线程的优点:

(1)可以同时完成多个任务;

(2)可以使程序的响应速度更快

(3)可以让占用大量处理时间的任务或当前没有进行处理的任务,定期将处理时间让给别的任务;

(4)可以随时停止任务;

(5)可以设置每个任务的优先级以优化程序性能。

2.1.2多线程的缺点:

(1)线程也是程序,所以线程需要占用内存,线程越多,占用内存也越多。

(2)多线程需要协调和管理,所以需要占用CPU时间以便跟踪线程。

(3)线程之间对共享资源的访问会相互影响,必须解决争用共享资源的问题

(4)线程太多会导致控制太复杂,最终可能造成很多程序缺陷。

2.1.3为什么可以多线程执行呢?

1、CPU运行速度太快,硬件处理速度跟不上,所以操作系统进行分时间片管理。这样,从宏观角度来说是多线程并发的,因为CPU速度太快,察觉不到,看起来是同一时刻执行了不同的操作。但是从微观角度来讲,同一时刻只能有一个线程在处理

2、目前电脑都是多核多CPU的,一个CPU在同一时刻只能运行一个线程,但是多个CPU在同一时刻就可以运行多个线程。

2.2线程实现

在C#中,线程是使用Thread类处理的,该类在System.Threading命名空间中。

使用Thread类创建线程时,只需要提供线程入口,线程入口告诉程序让这个线程做什么。

通过实例化一个Thread类的对象就可以创建一个线程。创建新的Thread对象时,将创建新的托管线程。

2.2.1 Thread构造函数

Thread类是是控制线程的基础类,位于System.Threading命名空间下,具有4个重载的构造函数:

名称 说明
Thread(ParameterizedThreadStart) 初始化 Thread 类的新实例,指定允许对象在线程启动时传递给线程的委托。要执行的方法是有参的。ParameterizedThreadStart委托的参数类型必须是Object的。如果使用的是不带参数的委托,不能使用带参数的Start方法运行线程,否则系统会抛出异常。
Thread(ParameterizedThreadStart, Int32) 初始化 Thread 类的新实例,指定允许对象在线程启动时传递给线程的委托,并指定线程的最大堆栈大小
Thread(ThreadStart) 初始化 Thread 类的新实例。要执行的方法是无参的。
Thread(ThreadStart, Int32) 初始化 Thread 类的新实例,指定线程的最大堆栈大小。

2.2.2Thread的方法

方法名称 说明
Abort() 终止本线程。
GetDomain() 返回当前线程正在其中运行的当前域。
GetDomainId() 返回当前线程正在其中运行的当前域Id。
Interrupt() 中断处于 WaitSleepJoin 线程状态的线程。
Join() 已重载。 阻塞调用线程,直到某个线程终止时为止。
Resume() 继续运行已挂起的线程。
Start() 执行本线程。
Suspend() 挂起当前线程,如果当前线程已属于挂起状态则此不起作用
Sleep() 把正在运行的线程挂起一段时间。

2.2.3创建线程的步骤:

1、编写线程所要执行的方法
2、实例化Thread类,并传入一个指向线程所要执行方法的委托。(这时线程已经产生,但还没有运行)
3、调用Thread实例的Start方法,标记该线程可以被CPU执行了,但具体执行时间由CPU决定

2.2.4线程常用属性

属性名称 说明
CurrentContext 获取线程正在其中执行的当前上下文。
CurrentThread 获取当前正在运行的线程。
ExecutionContext 获取一个 ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息。
IsAlive 获取一个值,该值指示当前线程的执行状态。
IsBackground 获取或设置一个值,该值指示某个线程是否为后台线程。
IsThreadPoolThread 获取一个值,该值指示线程是否属于托管线程池。
ManagedThreadId 获取当前托管线程的唯一标识符。
Name 获取或设置线程的名称
Priority 获取或设置一个值,该值指示线程的调度优先级
ThreadState 获取一个值,该值包含当前线程的状态

2.2.5线程的标识符

ManagedThreadId是确认线程的唯一标识符,程序在大部分情况下都是通过Thread.ManagedThreadId来辨别线程的。而Name是一个可变值,在默认时候,Name为一个空值 Null,开发人员可以通过程序设置线程的名称,但这只是一个辅助功能。

2.2.6线程优先级 

当线程之间争夺CPU时间时,CPU按照线程的优先级给予服务。高优先级的线程可以完全阻止低优先级的线程执行。.NET为线程设置了Priority属性来定义线程执行的优先级别,里面包含5个选项,其中Normal是默认值。除非系统有特殊要求,否则不应该随便设置线程的优先级别。

成员名称 说明
Lowest 可以将 Thread 安排在具有任何其他优先级的线程之后。
BelowNormal 可以将 Thread 安排在具有 Normal 优先级的线程之后,在具有 Lowest 优先级的线程之前。
Normal 默认选择。可以将 Thread 安排在具有 AboveNormal 优先级的线程之后,在具有 BelowNormal 优先级的线程之前。
AboveNormal 可以将 Thread 安排在具有 Highest 优先级的线程之后,在具有 Normal 优先级的线程之前。
Highest 可以将 Thread 安排在具有任何其他优先级的线程之前。

2.2.7线程状态 

通过ThreadState可以检测线程是处于Unstarted、Sleeping、Running 等等状态

2.3前台线程和后台线程

 前台线程:只有所有的前台线程都结束,应用程序才能结束。默认情况下创建的线程都是前台线程

后台线程:只要所有的前台线程结束,后台线程自动结束。通过Thread.IsBackground设置后台线程。必须在调用Start方法之前设置线程的类型,否则一旦线程运行,将无法改变其类型。

后台线程一般用于处理不重要的事情,应用程序结束时,后台线程是否执行完成对整个应用程序没有影响。如果要执行的事情很重要,需要将线程设置为前台线程。

2.4线程同步

所谓同步:是指在某一时刻只有一个线程可以访问变量。
如果不能确保对变量的访问是同步的,就会产生错误。
c#为同步访问变量提供了一个非常简单的方式,即使用c#语言的关键字Lock,它可以把一段代码定义为互斥段,互斥段在一个时刻内只允许一个线程进入执行,而其他线程必须等待。在c#中,关键字Lock定义如下:

Lock(expression)
{
   statement_block
}

expression代表你希望跟踪的对象
           如果你想保护一个类的实例,一般地,你可以使用this
           如果你想保护一个静态变量(如互斥代码段在一个静态方法内部),一般使用类名就可以了
而statement_block就算互斥段的代码,这段代码在一个时刻内只可能被一个线程执行。

在示例中大家可以去掉Lock尝试运行一次

进程与线程_第1张图片

2.5跨线程访问

2.6终止线程

若想终止正在运行的线程,可以使用Abort()方法。

3.进程与线程的关系

一个进程可以创建一个或多个线程,以执行与该进程关联的部分程序代码。在进程中可以有多个线程同时执行代码。
 

4.参考文献

https://www.cnblogs.com/HomeSapiens/p/16366835.html

你可能感兴趣的:(C#,C#,线程)