c#基础知识---多线程

2023-11-18

线程 被定义为程序的执行路径。每个线程都定义了一个独特的控制流。如果您的应用程序涉及到复杂的和耗时的操作,那么设置不同的线程执行路径往往是有益的,每个线程执行特定的工作。

线程是轻量级进程。一个使用线程的常见实例是现代操作系统中并行编程的实现。使用线程节省了 CPU 周期的浪费,同时提高了应用程序的效率。

到目前为止我们编写的程序是一个单线程作为应用程序的运行实例的单一的过程运行的。但是,这样子应用程序同时只能执行一个任务。为了同时执行多个任务,它可以被划分为更小的线程。

线程生命周期

线程生命周期开始于 System.Threading.Thread 类的对象被创建时,结束于线程被终止或完成执行时。

下面列出了线程生命周期中的各种状态:

  • 未启动状态:当线程实例被创建但 Start 方法未被调用时的状况。
  • 就绪状态:当线程准备好运行并等待 CPU 周期时的状况。
  • 不可运行状态:下面的几种情况下线程是不可运行的:

    • 已经调用 Sleep 方法
    • 已经调用 Wait 方法
    • 通过 I/O 操作阻塞
  • 死亡状态:当线程已完成执行或已中止时的状况。

主线程

在 C# 中,System.Threading.Thread 类用于线程的工作。它允许创建并访问多线程应用程序中的单个线程。进程中第一个被执行的线程称为主线程

当 C# 程序开始执行时,主线程自动创建。使用 Thread 类创建的线程被主线程的子线程调用。您可以使用 Thread 类的 CurrentThread 属性访问线程。

下面的程序演示了主线程的执行:

using System;
using System.Threading;

namespace MultithreadingApplication
{
    class MainThreadProgram
    {
        static void Main(string[] args)
        {
            Thread th = Thread.CurrentThread;
            th.Name = "MainThread";
            Console.WriteLine("This is {0}", th.Name);
            Console.ReadKey();
        }
    }
}

当上面的代码被编译和执行时,它会产生下列结果:

This is MainThread


创建线程

线程是通过扩展 Thread 类创建的。扩展的 Thread 类调用 Start() 方法来开始子线程的执行。

下面的程序演示了这个概念:

using System;
using System.Threading;

namespace MultithreadingApplication
{
    class ThreadCreationProgram
    {
        public static void CallToChildThread()
        {
            Console.WriteLine("Child thread starts");
        }
        
        static void Main(string[] args)
        {
            ThreadStart childref = new ThreadStart(CallToChildThread);
            Console.WriteLine("In Main: Creating the Child thread");
            Thread childThread = new Thread(childref);
            childThread.Start();
            Console.ReadKey();
        }
    }
}

当上面的代码被编译和执行时,它会产生下列结果:

In Main: Creating the Child thread
Child thread starts

管理线程

Thread 类提供了各种管理线程的方法。

下面的实例演示了 sleep() 方法的使用,用于在一个特定的时间暂停线程。

using System;
using System.Threading;

namespace MultithreadingApplication
{
    class ThreadCreationProgram
    {
        public static void CallToChildThread()
        {
            Console.WriteLine("Child thread starts");
            // 线程暂停 5000 毫秒
            int sleepfor = 5000; 
            Console.WriteLine("Child Thread Paused for {0} seconds", 
                              sleepfor / 1000);
            Thread.Sleep(sleepfor);
            Console.WriteLine("Child thread resumes");
        }
        
        static void Main(string[] args)
        {
            ThreadStart childref = new ThreadStart(CallToChildThread);
            Console.WriteLine("In Main: Creating the Child thread");
            Thread childThread = new Thread(childref);
            childThread.Start();
            Console.ReadKey();
        }
    }
}

当上面的代码被编译和执行时,它会产生下列结果:

In Main: Creating the Child thread
Child thread starts
Child Thread Paused for 5 seconds
Child thread resumes

销毁线程

Abort() 方法用于销毁线程。

通过抛出 threadabortexception 在运行时中止线程。这个异常不能被捕获,如果有 finally 块,控制会被送至 finally 块。

下面的程序说明了这点:

using System;
using System.Threading;

namespace MultithreadingApplication
{
    class ThreadCreationProgram
    {
        public static void CallToChildThread()
        {
            try
            {

                Console.WriteLine("Child thread starts");
                // 计数到 10
                for (int counter = 0; counter <= 10; counter++)
                {
                    Thread.Sleep(500);
                    Console.WriteLine(counter);
                }
                Console.WriteLine("Child Thread Completed");

            }
            catch (ThreadAbortException e)
            {
                Console.WriteLine("Thread Abort Exception");
            }
            finally
            {
                Console.WriteLine("Couldn't catch the Thread Exception");
            }

        }
        
        static void Main(string[] args)
        {
            ThreadStart childref = new ThreadStart(CallToChildThread);
            Console.WriteLine("In Main: Creating the Child thread");
            Thread childThread = new Thread(childref);
            childThread.Start();
            // 停止主线程一段时间
            Thread.Sleep(2000);
            // 现在中止子线程
            Console.WriteLine("In Main: Aborting the Child thread");
            childThread.Abort();
            Console.ReadKey();
        }
    }
}

当上面的代码被编译和执行时,它会产生下列结果:

In Main: Creating the Child thread
Child thread starts
0
1
2
In Main: Aborting the Child thread
Thread Abort Exception
Couldn't catch the Thread Exception 
  1. 线程函数通过委托传递,可以不带参数,也可以带参数(只能有一个参数),可以用一个类或结构体封装参数:

    using System;
    using System.Threading;
    
    namespace Test
    {
        class Program
        {
            static void Main(string[] args)
            {
                Thread t1 = new Thread(new ThreadStart(TestMethod));
                Thread t2 = new Thread(new ParameterizedThreadStart(TestMethod));
                t1.IsBackground = true;
                t2.IsBackground = true;
                t1.Start();
                t2.Start("hello");
                Console.ReadKey();
            }
    
            public static void TestMethod()
            {
                Console.WriteLine("不带参数的线程函数");
            }
    
            public static void TestMethod(object data)
            {
                string datastr = data as string;
                Console.WriteLine("带参数的线程函数,参数为:{0}", datastr);
            }
        }
    }
  2. 线程的销毁

    (1)线程自动销毁

    Thread a=new Thread(Method) th.start();

    线程方法Method执行完结,线程a也自动终止.

    (2)如果是无限循环需要手动销毁

    窗体应用程序的线程间通信

    .net 2.0以后加强了安全机制,不允许在winform中直接跨线程访问控件的属性。

    线程函数通过委托传递,是一种安全的线程间通信的方式。也是委托的功能之一。

    但C#也可以关闭线程安全保护,自由的调用其他线程生成的控件。只要加上

    Control.CheckForIllegalCrossThreadCalls = false;

    但不推荐使用。自己练习时可以写着玩一下。

  3. 本篇文章的第二段代码创建线程中,在2.0以后可以直接执行子线程,这样一来程序可以省略Main函数中的第一行代码。运行结果一样,似乎程序会更简单易懂点。如下:

    using System.Threading.Tasks;
    using System.Threading;
    namespace ConsoleApp
    {
        class Program
        {
            public static void CallToChildThread()
            {
                Console.WriteLine("Child thread starts");
            }
    
            static void Main(string[] args)
            {
                //ThreadStart childref = new ThreadStart(CallToChildThread);
                Console.WriteLine("In Main: Creating the Child thread");
                Thread childThread = new Thread(CallToChildThread);
                childThread.Start();
                Console.ReadKey();
            }
        }
    }
  4. C# 在 4.0 以后一共有3种创建线程的方式:

    •  1.Thread 自己创建的独立的线程, 优先级高,需要使用者自己管理。
    •  2.ThreadPool 有 .Net 自己管理, 只需要把需要处理的方法写好, 然后交个.Net Framework, 后续只要方法执行完毕, 则自动退出。
    •  3.Task 4.0 以后新增的线程操作方式, 类似 ThreadPool, 但效率测试比ThreadPool略高, Task对多核的支持更为明显,所以在多核的处理器中, Task的优势更为明显。
    class Program
    {  
        static void Main(string[] args)
        {  //独立创建线程
            Thread t = new Thread(ThreadProcess);
            t.Start(new object());
            
            //线程池
            ThreadPool.QueueUserWorkItem(ThreadProcess, new object());
            //Task方式创建线程
            System.Threading.Tasks.Task.Factory.StartNew(ThreadProcess, new object());
    
            //需要手动终止,当然现在终止可能线程还未运行完成,
            t.Abort();
        }
        private static void ThreadProcess(object tag)
        {
            int i = 100;
            while (i > 0)
            {
                Console.WriteLine(string.Format("i:{0} ", i));
                Thread.Sleep(10);
                i--;
            }
        }
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c#基础知识---多线程 的相关文章

  • 静态只读字符串数组

    我在我的 Web 应用程序中使用静态只读字符串数组 基本上数组有错误代码 我将所有类似的错误代码保存在一个数组中并检查该数组 而不是检查不同常量字符串中的每个错误代码 like public static readonly string m
  • 当我在组合框中选择一个项目时,如何防止 TextChanged 事件?

    我有一个TextChanged http msdn microsoft com en us library system windows forms control textchanged aspx我的事件ComboBox http msd
  • 使用 lambda 表达式注册类型

    我想知道如何在 UnityContainer 中实现这样的功能 container RegisterType
  • GetType() 在 Type 实例上返回什么?

    我在一些调试过程中遇到了这段代码 private bool HasBaseType Type type out Type baseType Type originalType type GetType baseType GetBaseTyp
  • 在c#中执行Redis控制台命令

    我需要从 Redis 控制台获取 客户端列表 输出以在我的 C 应用程序中使用 有没有办法使用 ConnectionMultiplexer 执行该命令 或者是否有内置方法可以查找该信息 CLIENT LIST是 服务器 命令 而不是 数据库
  • 查找进程的完整路径

    我已经编写了 C 控制台应用程序 当我启动应用程序时 不使用cmd 我可以看到它列在任务管理器的进程列表中 现在我需要编写另一个应用程序 在其中我需要查找以前的应用程序是否正在运行 我知道应用程序名称和路径 所以我已将管理对象搜索器查询写入
  • File.AppendText 尝试写入错误的位置

    我有一个 C 控制台应用程序 它作为 Windows 任务计划程序中的计划任务运行 此控制台应用程序写入日志文件 该日志文件在调试模式下运行时会创建并写入应用程序文件夹本身内的文件 但是 当它在任务计划程序中运行时 它会抛出一个错误 指出访
  • 在Linux中,找不到框架“.NETFramework,Version=v4.5”的参考程序集

    我已经设置了 Visual studio 来在我的 Ubuntu 机器上编译 C 代码 我将工作区 我的代码加载到 VS 我可以看到以下错误 The reference assemblies for framework NETFramewo
  • 为什么可以通过ref参数修改readonly字段?

    考虑 class Foo private readonly string value public Foo Bar ref value private void Bar ref string value value hello world
  • C# 存档中的文件列表

    我正在创建一个 FileFinder 类 您可以在其中进行如下搜索 var fileFinder new FileFinder new string C MyFolder1 C MyFolder2 new string
  • 类型约束

    我有以下类层次结构 class Header IEnumerable
  • 启动时的 Excel 加载项

    我正在使用 Visual C 创建 Microsoft Excel 的加载项 当我第一次创建解决方案时 它包含一个名为 ThisAddIn Startup 的函数 我在这个函数中添加了以下代码 private void ThisAddIn
  • 为什么从字典中获取时会得到 Action<> 的克隆?

    我有以下字典 private Dictionary
  • 在 NaN 情况下 to_string() 可以返回什么

    我使用 VS 2012 遇到了非常令人恼火的行为 有时我的浮点数是 NaN auto dbgHelp std to string myFloat dbgHelp最终包含5008角色 你不能发明这个东西 其中大部分为0 最终结果是 0 INF
  • 为什么这个二维指针表示法有效,而另一个则无效[重复]

    这个问题在这里已经有答案了 这里我编写了一段代码来打印 3x3 矩阵的对角线值之和 这里我必须将矩阵传递给函数 矩阵被传递给指针数组 代码可以工作 但问题是我必须编写参数的方式如下 int mat 3 以下导致程序崩溃 int mat 3
  • 等待 IAsyncResult 函数直至完成

    我需要创建等待 IAsyncResult 方法完成的机制 我怎样才能做到这一点 IAsyncResult result contactGroupServices BeginDeleteContact contactToRemove Uri
  • 在屏幕上获取字符

    我浏览了 NCurses 函数列表 似乎找不到返回已打印在屏幕上的字符的函数 每个字符单元格中存储的字符是否有可访问的值 如果没有的话Windows终端有类似的功能吗 我想用它来替换屏幕上某个值的所有字符 例如 所有a s 具有不同的特征
  • String.Empty 与 "" [重复]

    这个问题在这里已经有答案了 可能的重复 String Empty 和 有什么区别 https stackoverflow com questions 151472 what is the difference between string
  • 将数组作为参数传递

    如果我们修改作为方法内参数传递的数组的内容 则修改是在参数的副本而不是原始参数上完成的 因此结果不可见 当我们调用具有引用类型参数的方法时 会发生什么过程 这是我想问的代码示例 using System namespace Value Re
  • 不区分大小写的字符串比较 C++ [重复]

    这个问题在这里已经有答案了 我知道有一些方法可以进行忽略大小写的比较 其中涉及遍历字符串或一个good one https stackoverflow com questions 11635 case insensitive string

随机推荐

  • c语言实现面向对象编程(const * ,* const)

    c语言实现面向对象编程 面向对象思想 封装 继承 多态 代码实现 函数签名及返回值的约定 const 重载 参考了onlyshi的博客代码 orz传送门 参考了嵌入式实践一些代码 这里就不加了 面向对象思想 面向对象编程 OOP 并不是一种
  • 千年虫及UNIX时间

    转自 http hi baidu com dugucloud blog item b903ba803e5192c59123d99d html 千年虫何来 在上个世纪 许多计算机系统只用二进制7 8位数 足够十进制二位数使用 表示年份 比如说
  • ANR触发机制分析

    ANR是一套监控Android应用程序响应是否及时的机制 可以把发生ANR比作是引爆炸弹 那么整个流程包含三部分组成 埋定时炸弹 system server进程启动倒计时 在规定时间内如果目标应用进程没有干完所有的活 则system ser
  • MySQL的基本语法

    Welcome Huihui s Code World 接下来看看由辉辉所写的关于MySQL的相关操作吧 目录 Welcome Huihui s Code World 一 数据库 建立 查看 使用 删除 建库 查看数据库 使用数据库 删除数
  • decrypt()解密和encrypt()加密

    1 解密函数 select dbo decrypt StName from student 2 加密函数 select dbo encrypt StName from student
  • CxImage的编译及简单使用举例

    1 从http sourceforge net projects cximage 下载最新的CxImage 702源码 2 解压缩后 以管理员身份打开CxImageFull vc10 sln工程 在编译之前先将每个工程属性的Characte
  • Vue中props组件和slot标签的区别

    在 Vue 中 props 和 slot 都是组件之间进行通信的机制 它们的作用和应用场景有一些区别 props 是一种组件的数据传递机制 通过在父组件中以属性的形式向子组件传递数据 子组件接收这些数据 并可以进行相应的处理和渲染 prop
  • 每日一练——day2

    前言 小亭子正在努力的学习编程 接下来将开启编程题的练习 分享的文章都是学习的笔记和感悟 如有不妥之处希望大佬们批评指正 同时如果本文对你有帮助的话 烦请点赞关注支持一波 感激不尽 第一题 题目描述 链接 https www nowcode
  • Jenkins执行python代码

    在ide运行正常 在jenkins运行提示 模块不存在 找了一圈 原来是jenkin运行python的环境没设置 解决方式 在Manage Jenkins System Configuration Configure System中设置全局
  • WSL2连接到宿主Windows程序的网络代理设置

    WSL2想要连上宿主机Windows里设置的网络代理端口很是蛋疼 前置条件 PS C Users overlord gt wsl l v NAME STATE VERSION Ubuntu 20 04 Running 2 获取Host和WS
  • Consul的简介与安装

    1 Consul简介 Consul是一套开源的分布式服务发现和配置管理系统 由HashiCorp公司用Go语言开发 Consul提供了微服务系统中的服务治理 配置中心 控制总线等功能 这些功能中的每一个都可以根据需要单独使用 也可以一起使用
  • wsl配置

    文章目录 1 systemd服务开启 2 固定IP 2 1 官网的方案 2 2 通过WSL2的Linux子系统设置静态IP 2 3 其他方案 3 运行 Linux GUI 应用安装 Chrome 浏览器 此文接我放弃了VMware 1 sy
  • vue(3)调整 App.vue 文件和router路由

    调整 App vue 文件 我们先把默认项目里面没用的东西先删除掉 把代码调整为下面的样子
  • js延迟加载的性能优化

    js的延迟加载有助于提高页面的加载速度 特别是竞价优化站是有一定的好处 今天来说说我是如何优化竞价站打开速度 案例 http yzmb pengchenggroup cn 动态创建DOM方式
  • 每日一题——有向网的邻接矩阵、邻接表、逆邻接表创建、打印及深度、广度遍历

    有向网的三种创建和深度广度遍历 include
  • 基于骨骼的行为识别笔记(NTU RGBD数据集解析)

    目录 1 人类行为 层次 2 输入数据 3 基于骨架的行为识别 4 数据集 4 1 NTU RGBD 4 1 1 下载方式 4 1 2 Benchmark 5 相关论文 5 1 Skeleton based Action Recogniti
  • JavaScript的设计模式解析——工厂模式

    这几天一直在看 JavaScript高级程序设计 在第六章面向对象的程序设计中 自我感觉对于小白而而言 会一定程度的难以理解 什么意思啊 根本不明白哇等等 注意 大神请略过 小小码农 不敢妄言 首先 我们开门见山 什么是工厂模式 工厂模式能
  • javascript中Math.random()产生随机数及parseInt的作用

    Math random 是令系统随机选取大于等于 0 0 且小于 1 0 的小数 即 0 0 1 0 Math floor 返回小于参数x的最大整数 即对浮点数向下取整 比如Math floor 3 8 为3 一 在连续整数中取得一个随机整
  • WIN10 系统的 IRQL NOT LESS OR EQUAL 蓝屏问题

    WIN10 系统的 IRQL NOT LESS OR EQUAL 蓝屏问题 请参考以下步骤 1 Win r 输入 msconfig 2 点击 服务 标签卡 选择 隐藏所有的微软服务 然后点击全部禁用 若您启用了指纹识别功能 请不要关闭相关服
  • c#基础知识---多线程

    线程 被定义为程序的执行路径 每个线程都定义了一个独特的控制流 如果您的应用程序涉及到复杂的和耗时的操作 那么设置不同的线程执行路径往往是有益的 每个线程执行特定的工作 线程是轻量级进程 一个使用线程的常见实例是现代操作系统中并行编程的实现