C#学习笔记 线程操作

2023-11-17

完整代码在这里:https://github.com/techstay/csharp-learning-note

创建并使用线程

使用线程执行任务

要创建一个线程很简单,实例化一个System.Threading.Thread对象并向其构造函数传递一个无参无返回值的委托即可。创建完线程之后,线程并没有实际运行。要让其运行,需要调用其Start方法,这样会将其状态修改为就绪,可以随时被CPU调度运行。

public static void StartNewThread()
{
    Thread thread = new Thread(DoSomething);
    thread.Name = "线程1";
    PrintThreadInfo(thread);
    Console.WriteLine("线程大约3秒钟之后终止。");
    thread.Start();
    Console.WriteLine("线程结束之后按任意键继续。");
    Console.ReadKey();
}
private static void DoSomething()
{
    Thread.Sleep(3000);
    Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}已结束。");
}

线程带有很多属性,可以调用这些属性查看线程的状态。有些状态在线程停止之后会变为不可用的,试图调用不可用的属性会抛出异常。

public static void PrintThreadInfo(Thread thread)
{
    Console.WriteLine("显示线程信息:");
    Console.WriteLine("-------------------");
    Console.WriteLine($"当前线程名称:{thread.Name}");
    Console.WriteLine($"当前线程ID:{thread.ManagedThreadId}");
    Console.WriteLine($"是否是后台线程:{thread.IsBackground}");
    Console.WriteLine($"是否是线程池线程:{thread.IsThreadPoolThread}");
    Console.WriteLine($"当前线程优先级:{thread.Priority}");
    Console.WriteLine($"当前线程的状态:{thread.ThreadState}");
    Console.WriteLine("-------------------");
}

创建带有参数的线程

给线程传递的方法不仅可以是无参的,还可以带一个参数,用来执行一些需要更多信息的任务。要开出运行这样的线程,需要在其Start方法上传递线程要实际使用的参数:

public static void StartNewThreadWithArgument()
{
    Thread thread = new Thread(DoSomethingWithParameter);
    PrintThreadInfo(thread);
    Console.WriteLine("线程大约3秒钟之后终止。");
    thread.Start("一个字符串参数");
    Console.WriteLine("线程结束之后按任意键继续。");
    Console.ReadKey();
}
private static void DoSomethingWithParameter(object obj)
{
    Thread.Sleep(3000);
    Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}获取了{obj.GetType().Name}参数:{obj}。");
}

创建后台线程

线程可以分为前台线程和后台线程。只要应用程序中有一个前台线程还在运行,整个应用程序就不会停止。只有当所有前台线程终止的时候应用程序才会终止。后台线程则不同,只要前台线程都运行完毕,所有后台线程都会终止。

要创建后台线程,只需要将Thread类的IsBackground属性设为true即可。这样的话,线程就会变为后台线程。

public static void StartNewBackgroundThread()
{
    Thread thread = new Thread(DoSomething);
    thread.IsBackground = true;
    Console.WriteLine(Environment.NewLine + "线程会立即终止,因为它是后台线程:");
    PrintThreadInfo(thread);
    thread.Start();
}

线程的优先级

.NET线程本来是想设计为和Windows线程不同的线程模型,但是这个设计目标最后失败了。因此现在.NET线程就是Windows线程。Windows线程有32个优先级,从最低的0到最高的31。为了方便开发人员设定线程优先级,微软规定了6个进程优先级类和7个相对线程优先级。6个进程优先级类分别是Idle、Below Normal、Normal、Above Normal、High和Realtime。7个相对线程优先级类分别是Idle、Lowest、Below Normal、Normal、Above Normal,Highest和Time-Critical。一个线程的优先级是由它所在的进程优先级和相对线程优先级共同决定的。一般情况下,使用Normal级别的进程优先级和相对线程优先级就足够了。要修改线程的优先级,只需要修改Thread类中的Priority属性,向其传递ThreadPriority枚举中的值即可。

使用线程池线程

线程是一种宝贵的计算机资源,创建和销毁线程都需要进行大量工作。因此只有当进行单独长时间的计算任务或者指定一个线程进行专用任务的时候才需要自己创建线程。大多数时候,主需要使用线程池中的线程即可。

线程池是一个线程集合,里面包含了一定的线程,需要使用的时候可以向线程池申请线程,线程使用完毕之后不会被销毁,而是会回到线程池中一倍下次使用。因此使用线程池可以提高系统的效率。另外,线程池会根据系统的请求动态调整线程的数量,如果需要大量线程,线程池就会创建更多的线程;当系统闲置了一段时间以后,线程池就会销毁一些不用的线程。

要使用线程池,只需要向线程池类ThreadPool的静态方法QueueUserWorkItem传递WaitCallback委托和一个可选的state参数即可。其中WaitCallback委托是这样的:delegate void WaitCallback(object state);

public static void UseThreadPoolThreads()
{
    Random random = new Random();
    WaitCallback workWithoutParameter = (state) => Console.WriteLine($"显示随机数:{random.Next(1, 10)}");
    WaitCallback workWithOneParameter = (state) => Console.WriteLine($"显示参数:{state}");
    for (int i = 0; i < 5; ++i)
    {
        ThreadPool.QueueUserWorkItem(workWithoutParameter);
        ThreadPool.QueueUserWorkItem(workWithOneParameter, i);
    }
    //等待按键输入,防止程序退出(由于线程池都是后台线程)
    Console.ReadKey();
}

定时任务

可以使用System.Threading.Timer类来进行定时任务。该计时器会以给定的时间间隔执行任务,执行任务的时候会使用线程池线程。

初始化计时器的时候需要传递4个参数:第一个参数是一个TimerCallback类型的委托,这个委托接受一个object类型的状态参数,没有返回值,这个委托会在计时器满足条件的时候被调用;第二个参数是要传递给回调方法的状态参数,在不需要使用状态参数的时候可以为null;第三个参数dueTime是指计时器多长时间之后会启动,值为0的话立即启动,值为Timeout.Infinite的话永远不会启动;第四个参数period是指计时器经过多长时间再次调用回调方法,例如设为1000毫秒的话在计时器启动之后会每隔1000毫秒再次执行一次,如果值是Timeout.Infinite的话只会在根据dueTime的值执行一次,之后不会再执行。

在内部,线程池为所有的Timer对象分配一个线程,这个线程会在Timer对象满足条件的时候被唤醒,并将要执行的回调添加到线程池队列中。但是,如果回调方法比较费时,而计时器的间隔比较短,那么可能会有多个线程池线程同时执行。要防止这种情况,可以在初始化定时器的时候将period参数设为Timeout.Infinite,然后在回调方法中调用定时器的Change方法设置dueTime作为下一次执行的间隔,period参数仍然设为Timeout.Infinite。这样,就可以避免同时执行回调方法。

/// <summary>
/// 计数变量和计时器
/// </summary>
private static int number = 5;
private static Timer timer;
/// <summary>
/// 计数方法
/// </summary>
/// <param name="state"></param>
private static void Count(object state)
{
    if (number >= 0)
    {
        Console.Write(number--);
        timer.Change(1000, Timeout.Infinite);
    }

}
/// <summary>
/// 执行定时任务,计数器会每秒计数一次。
/// </summary>
public static void DoSomeRegularTasks()
{
    Console.WriteLine("开始执行定时任务:");
    timer = new Timer(Count, null, Timeout.Infinite, Timeout.Infinite);
    Console.WriteLine("开始计数,一秒一次,到0为止:");
    timer.Change(0, Timeout.Infinite);
    while (number >= 0)
    { }
    timer.Dispose();
    Console.WriteLine();
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C#学习笔记 线程操作 的相关文章

  • 如何使用 C# 以编程方式编辑 Power BI Desktop 文档参数或数据源?

    我有一个在 Power BI Desktop 中内置的报告模板 并保存为 pbix 或 pbit 文件 该模板使用DirectQuery SQL数据库作为数据源 而服务器地址和数据库名称被提取到参数中 还有一个参数包含一个ReportId
  • libtool 在 Ubuntu 13.04 上构建 thrift 0.9.1 时出错

    在 Ubuntu 13 04 上构建 thrift 0 9 1 支持 C C java C perl python 时出现此错误 configure 不带任何选项运行 make 不带任何选项运行 Making all in test mak
  • C# Outlook 从收件人获取 CompanyName 属性

    我目前正在使用 C 编写 Outlook 2010 AddIn 我想要的是从我从 AppointmentItem 中提取的 Recipient 对象中获取 CompanyName 属性 因此 有了 AppointmentItem 的收件人
  • 如何查明 .exe 是否正在 C++ 中运行?

    给定进程名称 例如 程序 exe C 标准库没有这样的支持 您需要一个操作系统 API 来执行此操作 如果这是 Windows 那么您将使用 CreateToolhelp32Snapshot 然后使用 Process32First 和 Pr
  • 类中是否可以有虚拟类声明?

    我正在为个人项目中框架的各个组件设置一个接口 我突然想到了一些我认为可能对接口有用的东西 我的问题是这是否可能 class a public virtual class test 0 class b public a public clas
  • 从时间列表中查找最接近的时间

    所以 这是场景 我有一个带有创建时间的文件 我想从该文件的创建时间最接近或相等的时间列表中选择一个时间 完成此操作的最佳方法是什么 var closestTime listOfTimes OrderBy t gt Math Abs t fi
  • 检测 TextBox 中的 Tab 键按下

    I am trying to detect the Tab key press in a TextBox I know that the Tab key does not trigger the KeyDown KeyUp or the K
  • 无法获取本地或参数的值,因为它在此指令指针处不可用,可能是因为它已被优化掉

    Visual Studio 2010 会删除 没有其他词 不安全块中函数参数之一中的数据 什么可能导致此错误 调试器显示以下消息 Cannot obtain value of local or argument as it is not a
  • 如何增加ofstream的缓冲区大小

    我想增加 C 程序的缓冲区大小 以便它不会过于频繁地写入 默认缓冲区是 8192 字节 我尝试使用 pubsetbuf 将其增加到 200K 原始代码 ofstream fq fastq1 cstr ios out fastq1 is a
  • 如何在新窗口中打开图像或pdf文件?

    我有一个 gridview 它包含文件名和文件路径 图像和 pdf 格式文件 其中我使用了模板字段 在该字段下放置了 1 个图像按钮 单击该图像按钮 即 查看 按钮 时 我想在新窗口中打开所选文件 这是我的代码 protected void
  • 在 C 语言中替换宏内的宏

    我正在尝试使代码部分可重用 我下面的评论片段没有达到我想要的效果 define NAME ABC define LOG SIZE NAME LEN 我想LOG SIZE决心ABC LEN 我尝试过使用 但没能让它发挥作用 LOG SIZE在
  • 如何在 EF Core 2.1 中定义外键关系

    我的 DAL 使用 EF Core 2 1 这就是我的模型的样子 一名用户只能拥有一种角色 Role entity kind of master public class Role public int RoleId get set pub
  • 在 C++ 代码 gdb 中回溯指针

    我在运行 C 应用程序时遇到段错误 在 gdb 中 它显示我的一个指针位置已损坏 但我在应用程序期间创建了 10 万个这样的对象指针 我怎样才能看到导致崩溃的一个 我可以在 bt 命令中执行任何操作来查看该指针的生命周期吗 谢谢 鲁奇 据我
  • 测验;这个编译了吗?如果是的话它会返回什么(我知道答案)

    我最近发现这个错字 if name find string npos 显然开发者的意思是输入 if name find string npos 但令我惊讶的是发现错误甚至编译 Wall Werror 没有尝试过 pedantic 那么 咖啡
  • MSVC编译器下使用最大成员初始化联合

    我正在尝试初始化一个LARGE INTEGER在 C 库中为 0 确切地说是 C 03 以前 初始化是 static LARGE INTEGER freq 0 在 MinGW 下它产生了一个警告 缺少成员 LARGE INTEGER Hig
  • Unity,c++ 本机插件字节数组不匹配

    在我的 C 本机插件中 我有一个调用 vector
  • 如何使用 VB.NET 打开受密码保护的共享网络文件夹?

    我需要在网络上打开受密码保护的共享文件夹才能访问 Access 97 数据库 如何打开文件夹并输入密码 在这里找到http www mredkj com vbnet vbnetmapdrive html http www mredkj co
  • 如何知道 HTTP 请求标头值是否存在

    我确信这很简单 但是却让我感到厌烦 我在 Web 应用程序中使用了一个组件 它在 Web 请求期间通过添加标头 XYZComponent true 来标识自身 我遇到的问题是 如何在视图中检查此组件 以下内容不起作用 if Request
  • IDisposable 的显式实现

    虽然有很多关于IDisposable在 SO 上找到 我还没有找到答案 我通常遵循这样的做法 当我的一个班级拥有一个IDisposable对象然后它也实现IDisposable并打电话Dispose在拥有的对象上 然而最近我遇到了一个类 它
  • 如何在c中断言两个类型相等?

    在 C 中如何断言两种类型相等 在 C 中 我会使用 std is same 但搜索 StackOverflow 和其他地方似乎只能给出 C 和 C 的结果 在C中没有办法做到这一点吗 请注意 这不是询问变量是否具有某种类型 而是询问两个类

随机推荐

  • DC-DC电路中,PCB Layout 布局及注意事项

    在DCDC电源电路中 PCB的布局对电路功能的实现和良好的各项指标来说都十分重要 本文以buck电路为例 简单分析一下如何进行合理PCB layout布局以及设计中的注意事项 如有问题 欢迎指正 首先 以最简单的BUCK电路拓扑为例 下图
  • androidx.lifecycle.ViewModel

    相关链接 深入了解架构组件之ViewModel
  • 抓包工具Charles(二)-移动端APP抓包(设置手机代理、安装证书)

    安装好Charles之后 还只能捕获电脑的接口请求 想要抓取移动设备的APP还需要设置代理 安装证书 文章目录 一 抓包原理 二 手机设置网络代理 1 查看电脑的IP地址 local IP address 2 设置手机网络代理 1 iOS设
  • 数据结构与算法----详解二叉树的遍历(迭代、递归)

    文章目录 实现二叉树的类 前序遍历 中序遍历 后序遍历 层次遍历 总结 作者简介 大家好我是小鱼干儿 是一个热爱编程 热爱算法的大三学生 蓝桥杯国赛二等奖获得者 个人主页 https blog csdn net qq 52007481 个人
  • 老毛桃u盘装系统linux,老毛桃U盘装系统教程详细步骤

    电脑用久了 就会觉得用起来很慢 还很卡 有时还有蓝屏的现象 为了解决这一问题 通常我们都会选择重装系统 如果你还是用光盘来装系统 那么你就OUT了 今天小编讲讲U盘怎么用 老毛桃 来给电脑重装系统 老毛桃是一个多系统模式的PE操作系统 一般
  • 机器学习必学数学基础系列之概率与统计

    课程目标机器学习必学数学基础系列之大数据矩阵基础适应人群大数据 人工智能开发人员课程简介本课程囊括了机器学习理论中所需要概率部分包括概率公理及推论 条件概率 贝叶斯公式 随机变量及其概率函数 CDF pdf 常用概率分布及其均值 方差 统计
  • 虚拟机网络配置、ssh免密配置、jdk和hadoop安装、Hadoop集群配置、格式化文件系统、关闭和启动集群、UI查看集群状态

    一 虚拟机网络配置 二 SSH免密登录公能配置 二 安装jdk 三 安装Hadoop 四 Hadoop集群配置 五 格式化文件系统 六 关闭和启动Hadoop集群 七 通过UI界面查看Hadoop运行状态 1 虚拟机网络配置 mkdir p
  • Python中一些语句的简洁写法

    Python拾珍 Python 提供了不少并不是完全必需的功能 使用这些功能可以写出更简洁 更可读或者更高效的代码 甚至有时候三者兼得 当然 不使用这些功能 我们依然可以写出好代码 阅读一些开源项目 github上很常见 经常可以看到这种简
  • 博士的年薪一般是多少万?

    作者 Dr YaIRhttps www zhihu com question 546293852 answer 3035449200 中科院北京某所的土博士毕业 拿到了中科院优博 留在中科院做助理研究员 工作2年了 本人不在院士组 不在杰青
  • MD5学习总结

    1 MD5简介 MD5 即消息摘要算法第五版 是一种被广泛使用的密码散列函数 散列算法的基本原理是 进行数据 如一段文字 运算 将原始数据变为另一段固定长度的值 MD5 可以产生出一个 128位 16字节 的散列值 hash value 用
  • kubeadm方式部署k8s最新版本V1.26.2

    Kubernetes核心概念 Master主要负责资源调度 控制副本 和提供统一访问集群的入口 核心节点也是管理节点 Node是Kubernetes集群架构中运行Pod的服务节点 Node是Kubernetes集群操作的单元 用来承载被分配
  • C++将一组数随机分成几个小组

    在生活中难免会遇到需要对一群人进行拆分小组 对于大的课题组的研究生还会分组开组会汇报确定名单这个事情 针对这些问题写出了下面的代码 include
  • python学习笔记之多线程练习ThreadPoolExecutor,map,submit

    主要练习了ThreadPoolExecutor map和submit的区别 推荐使用submit更灵活 import os import random import threading import requests as rq impor
  • Elementui - 下拉框(el-dropdown-menu组件)的使用方法

    Elementui 下拉框 el dropdown menu组件 的使用方法 官方文档 简单样式 此为指令事件 具体效果请看文档
  • 2023浙江省赛“信息安全管理与评估“--Reverse部分全部解析(高职组)

    2022全国职业技能大赛 信息安全管理与评估 高职组 任务书 2022全国职业技能大赛 信息安全管理与评估 任务书 第一阶段竞赛项目试题 第二阶段竞赛项目试题 第三阶段竞赛项目试题 任务3 Reverse 80分 2022全国职业技能大赛
  • GLES3.0中文API-glGetProgramInterface

    名称 glGetProgramInterface 查询程序中接口的属性 C 规范 void glGetProgramInterfaceiv GLuint program GLenum programInterface GLenum pnam
  • Hibernate复合主键的注解

    最近做项目用到了Hibernate框架 采用了纯面向对象的思想 使用ORM映射实体 在开发中 实体中出现了复合主键 不再是单一的属性作主键 由于采用了注解的方式 就不再使用xml文件进行配置了 而是直接在实体中进行注释 Hibernate注
  • Unity动画知识之二:Animator动画状态机

    文 拉撒路 上次我们讲过 Unity游戏动画从入门到住院 今天我们来讲一下动画状态机 好了 现在我们已经成功的导入了动画 接下来要玩的东西就很装13啦 因为大部分动画师是用不到这家伙的 需要掌握这个技能的 至少也是动画组长级别了 嗯 一个组
  • 找不到工作?对不起,这份测试面试题来晚了!

    1 测试测试与 测试的区别 首先alpha测试和beta都属于验收测试 这两种测试都需要用户参加 且都不能由程序员和测试员执行 广义上来讲 测试是 内测 测试是 公测 alpha测试是用户在开发环境或者是公司内部模拟实际操作环境的测试 测试
  • C#学习笔记 线程操作

    完整代码在这里 https github com techstay csharp learning note 创建并使用线程 使用线程执行任务 要创建一个线程很简单 实例化一个System Threading Thread对象并向其构造函数