C#的线程技术及操作(Thread类)

目录

一、线程基础

1.单线程 

2.多线程

(1)多线程的缺点

(2)多线程的缺点

二、线程操作之Thread类

1. Thread类的相关方法和属性

(1)示例源码

(2)生成效果

2.创建线程Start()方法

(1)示例源码

(2) 生成效果

​​​​​​3.线程的挂起与恢复Suspend()方法和Resume()方法

(1)Suspend()方法 

(2)Resume()方法

(3)该方法已废弃及替代方法

​​​​​4.线程休眠Sleep()方法

5.终止线程Abort()方法和Join()方法

(1)Abort()方法

(2)Join()方法


        每个正在操作系统上运行的应用程序都是一个进程一个进程可以包括一个或多个线程。线程是操作系统分配处理器时间的基本单元,在进程中可以有多个线程同时执行代码。每个线程都维护异常处理程序、调度优先级和一组系统用于在调度该线程前保存线程上下文的结构。线程上下文包括为使线程在线程的宿主进程地址空间中无缝地继续执行所需的所有信息,包括线程的CPU寄存器组和堆栈。

一、线程基础

1.单线程 

        单线程顾名思义,就是只有一个线程。默认情况下,系统为应用程序分配一个主线程,该线程执行程序中以Main()方法开始和结束的代码。

2.多线程

        需要用户交互的软件都必须尽可能快地对用户的活动做出反应,以便提供丰富多彩的用户体验,但同时它又必须执行必要的计算以便尽可能快地将数据呈现给用户,这时可以使用多线程来实现。

(1)多线程的缺点

要提高对用户的响应速度并且处理所需数据以便几乎同时完成工作,使用多线程是一种最为强大的技术,在具有一个处理器的计算机上,多线程可以通过利用用户事件之间很小的时间段在后台处理数据来达到这种效果。例如,通过使用多线程,在另一个线程正在重新计算同一应用程序中的电子表格的其他部分时,用户可以编辑该电子表格。

单个应用程序域可以使用多线程来完成以下任务。

☑ 通过网络与Web服务器和数据库进行通信。
☑ 执行占用大量时间的操作。
☑ 区分具有不同优先级的任务。
☑ 使用户界面可以在将时间分配给后台任务时仍能快速做出响应。 

(2)多线程的缺点

使用多线程有好处,同时也有坏处,建议一般不要在程序中使用太多的线程,这样可以最大限度地减少操作系统资源的使用,并可提高性能。

如果在程序中使用了多线程,可能会产生如下问题。

☑ 系统将为进程、AppDomain对象和线程所需的上下文信息使用内存。因此,可以创建的进程、AppDomain对象和线程的数目会受到可用内存的限制。
☑ 跟踪大量的线程将占用大量的处理器时间。如果线程过多,则其中大多数线程都不会产生明显的进度。如果大多数当前线程处于一个进程中,则其他进程中的线程的调度频率就会很低。
☑ 使用许多线程控制代码执行非常复杂,并可能产生许多bug。
☑ 销毁线程需要了解可能发生的问题并对那些问题进行处理。

二、线程操作之Thread

1. Thread类的相关方法和属性

        Thread类位于System.Threading命名空间下,System.Threading命名空间提供一些可以进行多线程编程的类和接口。除同步线程活动和访问数据的类(Mutex、Monitor、Interlocked和AutoResetEvent 等)外,该命名空间还包含一个ThreadPool类(它允许用户使用系统提供的线程池)和一个Timer类(它在线程池的线程上执行回调方法)。

        Thread类主要用于创建并控制线程、设置线程优先级并获取其状态。一个进程可以创建一个或多个线程以执行与该进程关联的部分程序代码,线程执行的程序代码由ThreadStart委托或ParameterizedThreadStart委托指定。

        线程运行期间,不同的时刻会表现为不同的状态,但它总是处于由ThreadState定义的一个或多个状态中。用户可以通过使用ThreadPriority枚举为线程定义优先级,但不能保证操作系统会接受该优先级。

        Thread类的常用属性及说明如表

属    性

说    明

    ApartmentState

   状取或设置此线程的单元状态

    CurrentContex

获取线程正在其中执行的当前上下文

    CurrentThread

   获取当前正在运行的线程

    isAlive

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

    ManagedThreadld

获取当前托管线程的唯一标识符

    Name

   获取或设置线程的名称

    Priority

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

    ThreadState

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

        Thread类的常用方法及说明如表

方   法

说   明

   Abort

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

   GetApartmentState

返回一个ApartmentState值,该值指示单元状态

   GetDomain

返回当前线程正在其中运行的当前域

   GetDomainID

返回唯一的应用程序域标识符

   Interrupt

中断处于WaitSleepJoin线程状态的线程

   Join

阻止调用线程,直到某个线程终止时为止

   ResetAbort

取消为当前线程请求的Abort

   Resume

维续已挂起的线程

   SetApartmentState

在线程启动前设置其单元状态

   Sleep

将当前线程阻止指定的毫秒数

   SpinWait

导致线程等待由iterations参数定义的时间量

   Start

使线程被安排进行执行

   Suspend

挂起线程,或者如果线程已挂起,则不起作用

   VolatileRead

读取字段值。无论处理器的数目或处理器缓存的状态如何,该值都是由计算机的任何处理器写入的最新值

   VolatileWrite

立即向字段写入一个值,以使该值对计算机中的所有处理器都可见

(1)示例源码

         使用Thread类的相关方法和属性,开始运行一个线程,并获得该线程的相关信息。

// 使用Thread类的相关方法和属性,
// 开始运行一个线程,并获得该线程的相关信息
using System.Threading;namespace _01
{public partial class Form1 : Form{private Button? button1;private RichTextBox? richTextBox1;public CancellationToken cancellationToken;public Form1()       {InitializeComponent();Load += Form1_Load;}private void Form1_Load(object? sender, EventArgs e){// // button1// button1 = new Button{Location = new Point(55, 126),Name = "button1",Size = new Size(75, 23),TabIndex = 0,Text = "确定",UseVisualStyleBackColor = true};button1.Click += Button1_Click;// // richTextBox1// richTextBox1 = new RichTextBox{Location = new Point(12, 12),Name = "richTextBox1",Size = new Size(160, 108),TabIndex = 1,Text = ""};// // Form1// AutoScaleDimensions = new SizeF(7F, 17F);AutoScaleMode = AutoScaleMode.Font;ClientSize = new Size(184, 161);Controls.Add(richTextBox1);Controls.Add(button1);Name = "Form1";StartPosition = FormStartPosition.CenterScreen;Text = "Form1";}private void Button1_Click(object? sender, EventArgs e){string strlnfo = string.Empty;         //定义一个字符串,用来记录线程相关信息Thread myThread =new(new ThreadStart(ThreadOut));//实例化Thread线程类对象myThread.Start();                         //启动主线程strlnfo = "线程唯一标识符:" + myThread.ManagedThreadId; strlnfo += "\n线程名称:" + myThread.Name;strlnfo += "\n线程状态;" + myThread.ThreadState.ToString(); strlnfo += "\n线程优先级:" + myThread.Priority.ToString(); strlnfo += "\n是否为后台线程:" + myThread.IsBackground; Thread.Sleep(1000);                     //使主线程休眠1秒钟richTextBox1!.Text = strlnfo;ThreadAbort(cancellationToken);//通过主线程阻止新开线程//myThread.Abort("退出");           //SYSLIB0006:不支持 Thread.AbortmyThread.Join();                         //等待新开的线程结束MessageBox.Show("线程运行结束");                                  }public static void ThreadOut(){MessageBox.Show("主线程开始运行");}/// <summary>/// 中止当前线程以外的线程/// </summary>/// <param name="cancellationToken">形参</param>static void ThreadAbort(CancellationToken cancellationToken){// If the CancellationToken is marked as "needs to cancel",// this will throw the appropriate exception.cancellationToken.ThrowIfCancellationRequested();}}
}

(2)生成效果

         首先生成主线程Form1()

 

         按下确定后,开启第二个线程ThreadOut()

        再按下确定后,开启第三个线程ThreadAbort()

 

         再按下确定后退出第二、第三线程,只剩下主线程Form1()

 

2.创建线程Start()方法

        创建一个线程:只需将其声明并为其提供线程起始点处的方法委托即可。

        创建新的线程:需要使用Thread类,Thread类具有接受一个ThreadStart委托或ParameterizedThreadStart委托的构造函数,该委托包装了调用Start()方法时由新线程调用的方法。创建了Thread类的对象之后,线程对象已存在并已配置,但并未创建实际的线程,这时,只有在调用Start()方法后,才会创建实际的线程。

        Start()方法用来使线程被安排执行,它有两种重载形式:

  • 导致操作系统将当前实例的状态更改为ThreadState.Running,语法如下
publie void Start()
  • 使操作系统将当前实例的状态更改为ThreadState.Running,并选择提供包含线程执行的方法要使用的数据的对象,语法如下
public void Start (Object parameter)
parameter:一个对象,包含线程执行的方法要使用的数据。
  •          如果线程已经终止,就无法通过再次调用Start()方法来重新启动。

(1)示例源码

         中通过实例化Thread类对象创建一个新的线程。最后调用Start()方法启动该线程。

// 通过实例化Thread类对象创建一个新的线。
// 最后调用Start()方法启动该线程
namespace _02
{class Program{/// <summary>/// 用线程起始点的ThreadStart委托创建该线程的实例/// </summary>static void Main(string[] args){Thread myThread;									//声明线程myThread = new Thread(new ThreadStart(CreateThread));myThread.Start();									//启动线程//myThread.Suspend();								//挂起线程, CS0618//myThread.Resume();							    //恢复挂起的线程, CS0618}public static void CreateThread(){Console.Write("创建线程");}}
}

(2) 生成效果

创建线程
F:\C#_TM\chapter25\02\bin\Debug\net8.0\02.exe (进程 20376)已退出,代码为 0。
按任意键关闭此窗口. . .

​​​​​​3.线程的挂起与恢复Suspend()方法和Resume()方法

        创建完一个线程并启动之后,还可以挂起、恢复、休眠或终止它,线程的挂起与恢复分别可以通过调用Thread类中的Suspend()方法和Resume()方法实现。

(1)Suspend()方法 

        Suspend()方法用来挂起线程,如果线程已挂起,则不起作用,语法如下。

public vaid Suspend()

        调用Suspend()方法挂起线程时,.NET允许要挂起的线程再执行几个指令,目的是为了到达.NET认为线程可以安全挂起的状态。

(2)Resume()方法

        Resume()方法用来继续已挂起的线程,语法如下。

public void Resume()

        通过Resume()方法来恢复被暂停的线程时,无论调用了多少次Suspend()方法,调用Resume()方法均会使另一个线程脱离挂起状态,并导致该线程继续执行。

(3)该方法已废弃及替代方法

        Thread.Suspend() 和 Thread.Resume() 这两个方法已过时。需要使用 AutoResetEvent,EventWaitHandle代替。

         废弃方法的示例在上例中注释掉的部分。替代方法的示例见作者其它文章。

​​​​​4.线程休眠Sleep()方法

        线程休眠主要通过Thread类的Sleep()方法实现,该方法用来将当前线程阻止指定的时间,它有两种重载形式:

        将当前线程挂起指定的时间,语法如下。

public static void Sleep/int millisecondsTimeout)
millisecondsTimeout:线程被阻止的毫秒数。指定零以指示应挂起此线程以使其他等待线程能够执行,指定Infinite以无限期阻止线程。 

        将当前线程阻止指定的时间,语法如下。

public static void Sleep(Time Span timeout)
timeout:线程被阻止的时间量的TimeSpan。指定零以指示应挂起此线程以使其他等待线程能够执行,指定Infinite以无限期阻止线程。

​​​​​​​5.终止线程Abort()方法和Join()方法

        终止线程可以分别使用Thread类的Abort()方法和Join()方法实现:

(1)Abort()方法

        Abort()方法用来终止线程,它有两种重载形式:

  • 终止线程,在调用此方法的线程上引发ThreadAbortException异常,以开始终止此线程的过程,语法如下。
public void Abort()
  • 终止线程,在调用此方法的线程上引发ThreadAbortException异常,以开始终止此线程并提供有关线程终止的异常信息的过程,语法如下。
public void Abort(Object statelnfo) 
stateInfo:一个对象,它包含应用程序特定的信息(如状态),该信息可供正被终止的线程使用。

         示例源码:

// 调用Thread类的Abort()方法终止已开启的线程
namespace _03
{class Program{/// <summary>/// 用线程起始点的ThreadStart委托创建该线程的实例/// </summary>/// <param name="args"></param>static void Main(string[] args){Thread myThread;									//声明线程myThread = new Thread(new ThreadStart(CreateThread));myThread.Start();                                   //启动线程
#pragma warning disable SYSLIB0006 // 类型或成员已过时myThread.Abort();                                   //终止线程
#pragma warning restore SYSLIB0006 // 类型或成员已过时}public static void CreateThread(){Console.Write("线程实例");}}}

         生成效果,即使经过禁止处理,也不能生成,因为被弃用了啊:

线程实例Unhandled exception. System.PlatformNotSupportedException: Thread abort is not supported on this platform.at System.Threading.Thread.Abort()at _03.Program.Main(String[] args) in F:\C#_TM\chapter25\03\Program.cs:line 16F:\C#_TM\chapter25\03\bin\Debug\net8.0\03.exe (进程 26936)已退出,代码为 -532462766。
按任意键关闭此窗口. . .

        线程的Abort()方法用于永久地停止托管线程。调用Abort()方法时,公共语言运行库在目标线程中引发ThreadAbortException异常,目标线程可捕捉此异常。一旦线程被终止,它将无法重新启动。

(2)Join()方法

        Join()方法用来阻止调用线程,直到某个线程终止时为止,它有3种重载形式:

  • 在继续执行标准的COM和SendMessage消息处理期间阻止调用线程,直到某个线程终止为止,语法如下。
public void Join()
  • 在继续执行标准的COM和SendMessage消息处理期间阻止调用线程,直到某个线程终止或经过了指定时间为止,语法如下。
public bool Join(int millisecondsTimeout)
☑ millisecondsTimeout:等待线程终止的毫秒数。
☑ 返回值:如果线程已终止,则为true;如果线程在经过了millisecondsTimeout参数指定的时间量后未终止,则为false。
  • 在继续执行标准的COM和SendMessage消息处理期间阻止调用线程,直到某个线程终止或经过了指定时间为止,语法如下。
public bool Join(TimeSpan timeout)
☑ timeout:等待线程终止的时间量的TimeSpan。
☑ 返回值:如果线程已终止,则为true;如果线程在经过了timeout参数指定的时间量后未终止,则为false。

        如果在应用程序中使用了多线程,辅助线程还没有执行完毕,在关闭窗体时必须关闭辅助线程,否则会引发异常。

        示例源码:

// 调用了Thread类的Join()方法等待线程终止
namespace _04
{class Program{/// <summary>/// 用线程起始点的ThreadStart委托创建该线程的实例/// </summary>static void Main(string[] args){Thread myThread;									//声明线程myThread = new Thread(new ThreadStart(CreateThread));myThread.Start();									//启动线程myThread.Join();									//阻止调用该线程,直到该线程终止}public static void CreateThread(){Console.Write("线程实例");}}
}
线程实例
F:\C#_TM\chapter25\04\bin\Debug\net8.0\04.exe (进程 19932)已退出,代码为 0。
按任意键关闭此窗口. . .

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/218055.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录算法训练营 | day50 动态规划 123.买卖股票的最佳时机Ⅲ,188.买卖股票的最佳时机Ⅳ

刷题 123.买卖股票的最佳时机Ⅲ 题目链接 | 文章讲解 | 视频讲解 题目&#xff1a;给定一个数组&#xff0c;它的第 i 个元素是一支给定的股票在第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。 注意&#xff1a;你不能同时参与多笔…

获取CAD图元名及图元信息(circle为例,用于选择集,对应dxf组码)

在CAD编程中往往需要用选择集&#xff0c;我们往往不知道相应图元对应的名称具体名字。比如我想选择所有的圆&#xff0c;ftype0,fdata应该是什么呢&#xff1f;是circle&#xff0c;acdbcircle&#xff0c;还是acadcircle? circle是一个对象&#xff0c;circle的vba类名为Ac…

SAP 散装物料简介

散装物料(Bulk Material),也叫做间接物料(Indirect Material),是一般企业在库存管理时常见的一种物料形式。散装物料专指那些价值小、消耗量大、消耗率高的物料件。这些物料组件同样服务于企业的生产活动,并且在企业的工作中心中被生产活动直接消耗(如螺丝钉、润滑油、…

海底数据中心:数据存储未来发展的新方向

随着信息技术的快速发展&#xff0c;数据需求量呈指数级增长&#xff0c;数据中心作为数据处理和存储的重要基础设施&#xff0c;其地位和作用愈发凸显。然而&#xff0c;传统的数据中心由于能耗大、碳排放高、土地占用等问题&#xff0c;已经难以满足可持续发展的需求。在此背…

Swin UNetR:把 UNet 和 Swin Transformer 结合

Swin UNetR&#xff1a;把 UNet 和 Swin Transformer 结合 网络结构使用指南 前置知识&#xff1a;Swin Transformer&#xff1a;将卷积网络和 Transformer 结合 Swin UNetR 结合 Swin Transformer 的上下文建模能力和 U-Net 的像素级别预测能力&#xff0c;提高语义分割任务的…

初始数据库 - 了解数据库

centos 7 版本当中安装 mysql 安装与卸载中&#xff0c;⽤⼾全部切换成为root&#xff0c;⼀旦 安装&#xff0c;普通⽤⼾是可以使用的。 卸载不需要的环境 首先&#xff0c;在安装之前&#xff0c;要先确定你当前系统当中是否已经有了mysql 的环境&#xff0c;如果你不想卸…

maui下sqlite演示增删改查

数据操作类 有分页 todoitemDatabase.cs&#xff1a; using SQLite; using TodoSQLite.Models;namespace TodoSQLite.Data {public class TodoItemDatabase{SQLiteAsyncConnection Database;public TodoItemDatabase(){}// 初始化数据库连接和表async Task Init(){if (Databa…

PPT插件-好用的插件-字距快速设置-大珩助手

字距快速设置 包含两端对齐、段首缩进、取消缩进、字间距、行间距、段后距 段首缩进 每次缩进两个字符&#xff0c;可对选中的文字、选中的多个文本对象两个层级操作 取消缩进 将缩进取消&#xff0c;可对选中的文字、选中的多个文本对象两个层级操作 字间距 预设了常用…

【GlobalMapper精品教程】065:连接SQL Server空间数据库并加载数据

Global Mapper是一个地图创建和编辑工具,无法像ArcGIS一样,基于SQL Server等大型关系型数据库。它本身也并不直接连接数据库。但是,Global Mapper可以与其他软件集成,以从数据库中获取数据并在地图上显示。本文讲述Global Mapper连接SLQ Server数据库的方法。 一、创建数据…

深入理解 Goroutines 和 Go Scheduler

本文将重点帮助您了解 Golang 中的 goroutines。Go 调度程序如何工作以在 Go 中实现最佳并发性能。我会尽力用简单的语言解释,这样你就可以理解了。 我们将介绍什么是操作系统中的线程和进程,什么是并发,为什么实现并发很难,以及 goroutines 如何帮助我们实现并发。然后,…

AtCoder ABC周赛2023 12/10 (Sun) D题题解

目录 原题截图&#xff1a; 题目大意&#xff1a; 主要思路&#xff1a; 注&#xff1a; 代码&#xff1a; 原题截图&#xff1a; 题目大意&#xff1a; 给定两个 的矩阵 和 。 你每次可以交换矩阵 的相邻两行中的所有元素或是交换两列中的所有元素。 请问要使 变换至…

JVM虚拟机系统性学习-垃圾回收器Serial、ParNew、Parallel Scavenge和Parallel Old

垃圾回收器 有 8 种垃圾回收器&#xff0c;分别用于不同分代的垃圾回收&#xff1a; 新生代回收器&#xff1a;Serial、ParNew、Parallel Scavenge老年代回收器&#xff1a;Serial Old、Parallel Old、CMS整堆回收器&#xff1a;G1、ZGC Serial&#xff1a;串行回收 Serial是…

Unity中实现ShaderToy卡通火(总结篇)

文章目录 前言一、把卡通火修改为后处理效果1、在Shader属性面板定义属性接收帧缓存纹理2、在片元着色器对其纹理采样后&#xff0c;与卡通火相加输出请添加图片描述 二、我们自定义卡通火1、修改 _CUTOFF 使卡通火显示在屏幕两侧2、使火附近屏幕偏红色 前言 在之前的文章中&a…

【IC验证】perl脚本——分析前/后仿用例回归情况

目录 1 脚本名称 2 脚本使用说明 3 nocare_list文件示例 4 脚本执行方法 5 postsim_result.log文件示例 6 脚本代码 1 脚本名称 post_analysis 2 脚本使用说明 help&#xff1a;打印脚本说明信息 命令&#xff1a;post_analysis help 前/后仿结束后&#xff0c;首先填…

计算机毕业设计 SpringBoot的企业内管信息化系统 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

首场“解数Talk” 直播来了——大模型语料数据联盟开源数据集解读

一、解数 Talk 介绍 为帮助广大开发者更好地了解大模型语料数据联盟发布的AI大模型语料数据&#xff0c;沟通大模型企业在AI视角下的数据需求&#xff0c;不断服务大模型产业生态和落地应用&#xff0c;联盟发起单位上海人工智能实验室联合成员单位共同打造“解数 Talk”系列直…

java系列-LinkedHashMap怎么实现LRU

1.定义变量accessOrder public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> {final boolean accessOrder;public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {super(initialCapacity, loadFactor…

《地理信息系统原理》笔记/期末复习资料(9. 网络地理信息系统)

目录 9. 网络地理信息系统 9.1. 概述 9.1.1. 网络GIS概念 9.1.2. 网络GIS体系结构 9.1.3. 网络GIS内容体系 9.2. 分布式网络GIS 9.2.1. 分布式网络GIS概念 9.2.2. 分布式主要技术 9.3. WebGIS 9.3.1. WebGIS概念 9.3.2. WebGIS分类与特点 9.3.3. WebGIS技术框架 9…

SimCLR损失函数详解

图片来源&#xff1a;Self-Supervised Learning 超详细解读 (二)&#xff1a;SimCLR系列 文章目录 1. 数据增强2. 获得图片表征3. 正样本和负样本构建4. 计算相似度5. 计算图片之间相似的概率6. 损失函数为什么需要大规模的batchsize&#xff1f; 1. 数据增强 有一批batchsize…

LeetCode-旋转链表问题

1.旋转链表 题目描述&#xff1a; 给你一个链表的头节点 head &#xff0c;旋转链表&#xff0c;将链表每个节点向右移动 k 个位置。 思路&#xff1a; 这里向右移动k个位置&#xff0c;相当于从链表的倒数第k个节点处断开&#xff0c;之后再将断开的两个子链表按照相反顺序…