C#线程详解及应用示例

news2024/11/25 12:24:22

 简介

在编写应用程序实现业务功能过程中,为解决吞吐量和响应效率的问题,我们会用到多线程、异步编程两项重要的技术。通过它们来提高应用程序响应和高效。应用程序每次运行都会启动一个进程(进程是一种正在执行的程序),而进程中可以包含一个或多个线程,由应用程序入口直接或间接执行的命令都由默认线程(或主线程)执行。

线程概述

线程是任务调度和执行的基本单位。线程是进程的一部分,线程共享该进程的资源。使用多线程技术可解决部分代码同时执行的需求,更好地利用资源。在介绍 C# 线程相关技术点前,先梳理同步、异步、线程安全等几个概念。

1、同步是指多个线程严格按照顺序依次执行,当前线程执行完成后再执行下一个线程。

2、异步是指多个线程的执行顺序是不确定的,每个线程都独立执行,互不干扰。

3、线程安全是指多线程访问共享资源时,保证数据的一致性和完整性,避免出现数据竞争和不一致的结果。

4、争用条件是指多个线程共享访问同一数据时,每个线程都尝试操作该数据,从而导致数据被破坏。

实现方式

在C#语言中,可以通过 Thread 、ThreadPool、Task、Parallel 等类来实现多线程,根据具体特点和场景选择合适的方式来实现。

使用 Thread

通过Thread类实例化 Thread 对象是在构造方法中传入委托对象,Thread 类的构造方法的参数 ThreadStart(无参无返回值的委托)和 ParameterizedThreadStart(有一个object类型参数但无返回值的委托)两种。

通过示例来了解实现无参数的线程


using System;
using System.Threading;
using System.Windows.Forms;

namespace Fountain.WinForm.ThreadApp
{
  public partial class ThreadForm : Form
  {
    public ThreadForm()
    {
      InitializeComponent();
    }
    /// <summary>
    /// 显示时间
    /// </summary>
    public void DisplayTime()
    {
      try 
      {
        while (true)
        {
          this.LabelCurrentTime.Invoke(new EventHandler(delegate
          {
            // 访问主界面的控件
            this.LabelCurrentTime.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
          }));
          Thread.Sleep(10);
        }
      }
      catch 
      {
      }
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void ThreadForm_Load(object sender, EventArgs e)
    {
      try
      {
        // 形式一
        Thread thread = new Thread(DisplayTime);
        // 设置为后台线程
        thread.IsBackground = true;
        // 开启线程
        thread.Start();
        // Lambda表达式代替方法DisplayTime
        Thread lambdaThread =new Thread(()=> 
        {
          this.LabelThreadId.Invoke(new EventHandler(delegate
          {
            // 访问主界面的控件
            this.LabelThreadId.Text = string.Format("Lambda代码段为执行的任务");
          }));
        });
         // 设置为后台线程
        lambdaThread.IsBackground = true;
        // 开启线程
        lambdaThread.Start();
      }
      catch
      {
      }
    }
  }
}

通过示例来了解实现带参数的线程

using System;
using System.IO;
using System.Threading;
using System.Windows.Forms;

namespace Fountain.WinForm.ThreadApp
{
  public partial class ThreadForm : Form
  {
    public ThreadForm()
    {
      InitializeComponent();
    }
    /// <summary>
    /// 删除日志文件
    /// </summary>
    public void Delete(object retentionTime)
    {
      // 日志目录
      string logDirectory = string.Format("{0}{1}", AppDomain.CurrentDomain.BaseDirectory, "Log");
      try
      {
        if (Directory.Exists(logDirectory))
        {
          // 获取所有匹配的日志文件
          string[] files = Directory.GetFiles(logDirectory, "*.log");
          // 遍历删除
          foreach (string file in files)
          {
            if (File.GetCreationTime(file).AddDays(Convert.ToInt32(retentionTime)) < DateTime.Now)
            {
              File.Delete(file);
            }
          }
        }
      }
      catch
      {
      }
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void ThreadForm_Load(object sender, EventArgs e)
    {
      try
      {
        //声明线程实例
        Thread parameterThread = new Thread(Delete);
        // 设置为后台线程
        parameterThread.IsBackground = true;
        // 开始执行线程,传递参数
        parameterThread.Start(10); 
      }
      catch
      {
      }
    }
  }
}

其它常用方法

方法描述
Join()阻塞调用线程,直到某个线程终止或执行完。
Suspend()标记线程为挂起,进入暂停状态。
Resume()继续已经挂起的线程。
Interrupt()中断处于 WaitSleepJoin 状态的线程。
使用 ThreadPool

ThreadPool 是C# 提供的一个线程池,该线程池可用于执行任务、发送工作项、处理异步 I/O、代表其他线程等待以及处理计时器。

QueueUserWorkItem 方法

是用于将需要执行一个方法提交到线程池的队列。当线程池中有可用线程时,方法被执行。

通过示例解通过线程池的实现方式


using System;
using System.IO;
using System.Threading;
using System.Windows.Forms;
namespace Fountain.WinForm.ThreadApp
{
  public partial class ThreadPoolForm : Form
  {
    public ThreadPoolForm()
    {
        InitializeComponent();
    }
    /// <summary>
    /// 窗体加载
    /// </summary>
    private void ThreadPoolForm_Load(object sender, EventArgs e)
    {
      try
      {
        // 最大线程数
        int workerThreads = 0;
        // 异步 I/O 最大线程数
        int completionPortThreads = 0;
        // 
        ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads);
        this.LabelMaxThreads.Text = string.Format("{0}{1}", this.LabelMaxThreads.Text, workerThreads);
        // 启动线程
        ThreadPool.QueueUserWorkItem(new WaitCallback(Delete),10);
      }
      catch 
      {
      }
    }
    /// <summary>
    /// 删除日志文件
    /// </summary>
    public void Delete(object retentionTime)
    {
      // 日志目录
      string logDirectory = string.Format("{0}{1}", AppDomain.CurrentDomain.BaseDirectory, "Log");
      try
      {
        if (Directory.Exists(logDirectory))
        {
          // 获取所有匹配的日志文件
          string[] files = Directory.GetFiles(logDirectory, "*.log");
          // 遍历删除
          foreach (string file in files)
          {
            if (File.GetCreationTime(file).AddDays(Convert.ToInt32(retentionTime)) < DateTime.Now)
            {
              File.Delete(file);
            }
          }
        }
        this.LabelCompleted.Invoke(new EventHandler(delegate
        {
            // 访问主界面的控件
            this.LabelCompleted.Text = "线程执行完成";
        }));
      }
      catch
      {
      }
    }
  }
}

RegisterWaitForSingleObject 方法

是将指定的操作方法注册到线程池,在接收到事件处理器信号、指定等待的时间超时,辅助线程执行此操作的方法。

参数描述
waitObject注册等待 WaitHandle 的委托。用ManualResetEvent 或 AutoResetEvent
callback在接收到事件处理器信号、指定等待的时间超时要执行的回调方法。
state传递给回调方法的参数
millisecondsTimeOutInterval等待的时间间隔,以毫秒为单位。0:立即返回,-1:无限等待。
executeOnlyOnce指示回调是否只执行一次。

示例:每隔1秒刷新界面时间


using System;
using System.IO;
using System.Threading;
using System.Windows.Forms;
namespace Fountain.WinForm.ThreadApp
{
  public partial class ThreadPoolForm : Form
  {
    //创建一个AutoResetEvent,初始状态为未触发状态
    private AutoResetEvent autoResetEvent = new AutoResetEvent(false);
    /// <summary>
    /// 
    /// </summary>
    public ThreadPoolForm()
    {
      InitializeComponent();
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void ThreadPoolForm_Load(object sender, EventArgs e)
    {
      try
      {
        object state = new object();
        // 每隔1秒刷新界面时间
        ThreadPool.RegisterWaitForSingleObject(autoResetEvent,new WaitOrTimerCallback(TimerCallback), state, 1000,false);
      }
      catch 
      {
      }
    }
    /// <summary>
    /// 界面时间
    /// </summary>      
    private  void TimerCallback(object state, bool timedOut)
    {
      // 每隔1秒显示
      this.LabelCurrentTime.Invoke(new EventHandler(delegate
      {
          // 访问主界面的控件
          this.LabelCurrentTime.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
      }));
    }
  }
}

关于ManualResetEvent 和 AutoResetEvent 的用法,后续展开。

使用 Task

Task 是C# (.NET 4.0)提供的一种简单和强大的异步处理类。除Dispose()之外所有成员都是线程安全的,并且可以同时从多个线程使用。

创建任务

1、通过构造函数

// 创建
Task task = new Task(()=>
{
// 界面显示时间
this.LabelCurrentTime.Invoke(new EventHandler(delegate
  {
// 访问主界面的控件
this.LabelCurrentTime.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
  }));
});
// 启动
task.Start();
// 定义一个任务
Action<object> action = (object retentionTime) =>
{
  Delete(retentionTime);
};
// 创建
Task deleteTask = new Task(action, 10);
// 启动
deleteTask.Start();

2、使用 TaskFactory.StartNew 方法

// 创建
Task taskFactory = Task.Factory.StartNew(() => {
  // 界面显示时间
  this.LabelCurrentTime.Invoke(new EventHandler(delegate
  {
    // 访问主界面的控件
    this.LabelCurrentTime.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
  }));
});
启动
taskFactory.Start();

3、使用 Run 方法 .NET 4.5之后的版本

// 创建并启动
Task.Run(() => 
{
  // 显示时间
  this.LabelCurrentTime.Invoke(new EventHandler(delegate
  {
    // 访问主界面的控件
    this.LabelCurrentTime.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
  }));
});
使用 Parallel

Parallel 是 C# (.NET 4.0) 提供的对并行循环和区域的支持。其提供三个静态方法作为结构化并行的基本形式。

Invoke:并行调用多个任务

/// <summary>
/// 显示时间
/// </summary>
public void DisplayTime()
{
}
/// <summary>
/// 删除日志文件
/// </summary>
private void Delete()
{
}
/// <summary>
/// 按钮事件
/// </summary>
private void ButtonTaskk_Click(object sender, EventArgs e)
{
    Parallel.Invoke(DisplayTime, Delete);
}

For:循环执行并行方法

Parallel.For(0, 20, i =>
{
  this.TextBoxResult.BeginInvoke(new EventHandler(delegate
  {
    // 访问主界面的控件
    this.TextBoxResult.Text += string.Format("执行次数:{0},开始时间:{1}{2}", i, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), Environment.NewLine);
  }));
});

执行并行方法

List<string> weekend = new List<string>();
weekend.Add("星期日");
weekend.Add("星期一");
weekend.Add("星期二");
weekend.Add("星期三");
weekend.Add("星期四");
weekend.Add("星期五");
weekend.Add("星期六");

Parallel.ForEach(weekend,day =>
{
  this.TextBoxResult.BeginInvoke(new EventHandler(delegate
  {
    // 访问主界面的控件
    this.TextBoxResult.Text += string.Format("{0}{1}", day, Environment.NewLine);
  }));
});

小结

以上都是线程相关的内容,线程属于C#的高级语法,其内容有很多,使用情况也很多。希望通过本篇对大家对线程后续的学习有帮助,敬请关注后续内容。

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

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

相关文章

基于node.js宜家宜业物业管理系统【附源码】

基于node.js宜家宜业物业管理系统 效果如下&#xff1a; 系统首页界面 业主登录界面 停车位页面 小区公告页面 管理员登录界面 管理员功能界面 物业管理员管理界面 缴费信息管理界面 物业管理员功能界面 研究背景 近年来互联网技术飞速发展&#xff0c;给人们的生活带来了极…

【数据分享】全国金融业-股票发行量和筹资额(1991-2021年)

数据介绍 一级标题指标名称单位金融业股票发行量亿股金融业A股发行量亿股金融业H股,N股发行量亿股金融业B股发行量亿股金融业股票筹资额亿元金融业A股筹资额亿元金融业配股筹资额亿元金融业H股,N股筹资额亿元金融业B股筹资额亿元 注&#xff1a;本文中的数据仅为示例&#xf…

Burp Suite Professional 2024.9 for macOS x64 ARM64 - 领先的 Web 渗透测试软件

Burp Suite Professional 2024.9 for macOS x64 & ARM64 - 领先的 Web 渗透测试软件 世界排名第一的 Web 渗透测试工具包 请访问原文链接&#xff1a;https://sysin.org/blog/burp-suite-pro-mac/ 查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1…

【数据结构】分治算法经典: 快速排序详解

快速排序&#xff08;Quicksort&#xff09;是一种高效的排序算法&#xff0c;最早由Tony Hoare在1960年提出。它采用了分治&#xff08;Divide and Conquer&#xff09;策略&#xff0c;平均时间复杂度为 O ( n log ⁡ n ) O(n \log n) O(nlogn)&#xff0c;在大多数实际应用…

双十一开启极速达夜派;黑神话获泰国年度最佳游戏;AI 模型可帮助识别 17000 多种疾病的候选药物....| 网易数智日报

双 11 菜鸟在北京、上海、广州、杭州等城市开启「预售极速达夜派」服务 10 月 21 日&#xff0c;菜鸟在北京、上海、广州、杭州等城市开启「预售极速达夜派」服务&#xff0c;批量大促包裹实现小时级送达。 据介绍&#xff0c;在消费者支付尾款前&#xff0c;菜鸟供应链就已经…

项目结构(后端+前端)(若依)

项目结构&#xff08;后端前端&#xff09; 文章目录 项目结构&#xff08;后端前端&#xff09;前言一、后端结构1.若依 二、前端结构1. 总结 前言 方便了解项目结构 提示&#xff1a;以下是本篇文章正文内容&#xff1a; 一、后端结构 1.若依 com.ruoyi ├── ruoyi-adm…

【C++干货篇】——类和对象的魅力(四)

【C干货篇】——类和对象的魅力&#xff08;四&#xff09; 1.取地址运算符的重载 1.1const 成员函数 将const修饰的成员函数称之为const成员函数&#xff0c;const修饰成员函数放到成员函数参数列表的后面。const实际修饰该成员函数隐含的this指针&#xff08;this指向的对…

Flutter Container容器组件实战案例

The Container widget is your design toolkit. It’s like the master builder that helps you structure and style your UI elements with precision. Whether you’re creating simple designs or complex layouts, the Container is your trusty tool for the job. “容器…

全能大模型GPT-4o体验和接入教程

GPT-4o体验和接入教程 前言一、原生API二、Python LangchainSpring AI总结 前言 Open AI发布了产品GPT-4o&#xff0c;o表示"omni"&#xff0c;全能的意思。 GPT-4o可以实时对音频、视觉和文本进行推理&#xff0c;响应时间平均为 320 毫秒&#xff0c;和人类之间对…

【C++篇】深度解析类与对象(上)

目录 引言 一、类的定义 1.1类定义的基本格式 1.2 成员命名规范 1.3 class与struct的区别 1.4 访问限定符 1.5 类的作用域 二、实例化 2.1 类的实例化 2.2 对象的大小与内存对齐 三、this 指针 3.1 this指针的基本用法 3.2 为什么需要this指针&#xff1f; 3.3 t…

Java毕业设计 基于SpringBoot发卡平台

Java毕业设计 基于SpringBoot发卡平台 这篇博文将介绍一个基于SpringBoot发卡平台&#xff0c;适合用于Java毕业设计。 功能介绍 首页 图片轮播 商品介绍 商品详情 提交订单 文章教程 文章详情 查询订单  查看订单卡密 客服   后台管理 登录 个人信息 修改密码 管…

成都爱尔胡建斌院长讲解年纪大眼花?小心黄斑变性!

中老年朋友觉得年龄增加后&#xff0c;眼睛出现模糊是常态&#xff0c;但是眼花不止“老花眼”一种&#xff0c;要小心的是眼底病变&#xff01; 眼花的形式有很多种&#xff0c;如果视线中间出现暗点视物变得模糊&#xff0c;很难看清周围的人脸&#xff0c;在看书看手机这种…

MATLAB(Octave)混电动力能耗评估

&#x1f3af;要点 处理电动和混动汽车能耗的后向和前向算法模型(simulink)&#xff0c;以及图形函数、后处理函数等实现。构建储能元数据信息&#xff1a;电池标称特性、电池标识符等以及静止、恒定电流和恒定电压等特征阶段。使用电流脉冲或要识别的等效电路模型类型配置阻抗…

jmeter学习(6)逻辑控制器-循环

循环执行 1、循环读取csv文件的值 2、foreach 读取变量&#xff0c;变量数字后缀有序递增&#xff0c;通过counter实现 ${__V(typeId${typeIdNum})} beansell断言 String typeIdNum vars.get("typeIdNum"); String response prev.getResponseDataAsString(); …

MAC 安装HomeBrew-亲自尝试,100%会成功

文章来自这里: https://zhuanlan.zhihu.com/p/620975942 安装指令&#xff1a; /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"执行完成后&#xff0c;输入下列命令验证 brew --version

AcWing 875:快速幂

【题目来源】https://www.acwing.com/problem/content/877/【题目描述】 给定 组 &#xff0c;对于每组数据&#xff0c;求出 的值。【输入格式】 第一行包含整数 。 接下来 行&#xff0c;每行包含三个整数 。【输出格式】 对于每组数据&#xff0c;输出一个结果&#xff0…

初阶数据结构【3】--单链表(比顺序表还好的一种数据结构!!!)

本章概述 前情回顾单链表实现单链表彩蛋时刻&#xff01;&#xff01;&#xff01; 前情回顾 咱们在上一章博客点击&#xff1a;《顺序表》的末尾&#xff0c;提出了一个问题&#xff0c;讲出了顺序表的缺点——有点浪费空间。所以&#xff0c;为了解决这个问题&#xff0c;我…

计算机网络-RSTP快速生成树基础概念

一、STP概念复习 在之前的学习中我们已经学习了STP的概念与作用。参考文章&#xff1a;计算机网络-生成树基础 STP&#xff08;Spanning Tree Protocol&#xff0c;生成树协议&#xff09; 是一种用于在局域网中消除数据链路层物理环路的协议。主要作用是防止交换机冗余链路产生…

app端文章列表查询-详细教程(上)

app端文章列表查询 一、数据库方面 有关文章的表垂直拆分成了三张表&#xff1a;文章基本信息表&#xff08;字段有文章id、文章作者、文章标题、发布时间等&#xff09;、文章配置表&#xff08;字段有文章id、文章是否可评论、文章可转发、是否已下架、是否已删除等&#x…

MySQL 基础查询

1、DISTINCT select DISTINCT EMPLOYEE_ID ,FIRST_NAME from employees 按照ID去重&#xff0c;DISTINCT的字段要放在前面&#xff0c;不会再继续在FIRST_NAME上去重判断&#xff1b; 如果需要多字段去重&#xff0c;需要用到group by&#xff0c;这个后面讲&#xff1b; …