当前位置: 首页 > article >正文

C#笔记8 线程是什么?多线程怎么实现和操作?

这和前面的学习内容可能有点不太连贯,但是呢我们一般来说的学习就是遇到什么困难就去学习什么,这也是为什么看那些循序渐进的教程虽然学的很饱满,但是我们有时会学了前面忘记了后面,或者对某个板块理解不深,乃至于写代码虽然能看懂ai的解释,却不能融会贯通。

就好像现在:我学习网络通信,却遇到了关于同步异步的问题,虽然本科时有粗略学习过一系列多线程之类的概念,但是在具体问题中发现远远不够,十分迷糊。于是决定学习这一章。

线程是什么?

每个操作系统上运行的应用程序都是一个进程,一个进程可以包括一个或多个线程。

线程是操作系统分配处理器时间的基本单元。

在进程中可以有多个线程。

线程上下文

线程上下文是指保证线程在宿主进程地址空间中无缝继续运行所必须得所有信息。

单线程

只有一个线程,从头执行到尾的程序叫做单线程程序,默认情况下系统会给应用程序分配一个入口也就是常见的Main方法。如果你新建一个winform程序,你可以搜索Main方法看看它创建了什么。

    internal static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }

怎么样?一个窗体界面运行在一个线程,于是我们在其他线程中,比如网络操作,文件读写的线程中如果修改这里的窗体界面,会报一个很常见很常见的错误哦。

 当然,这个我们后面再说。

什么是多线程?

很好,我们刚刚说过了,用户界面在一个线程上运行,我们又知道,线程是分配处理器时间的最小单元,那么如果我们只有一个线程,如果遇到一个任务需要很长时间,就只能等待这个事情做完了,相应的,我们的用户界面也会卡住了,这是古早一些软件的常见情况,点击一个按钮触发了事件之后,很长一段时间都没有反应。。。

于是我们就尝试使用多个线程来运行我们的程序,遇到需要占用时间的事情我们就新开一个线程,然后给他扔到我们的后台去。这样我们前台的用户界面就不会卡顿,还能继续处理用户的其他操作,这可比原来强多了。

多线程的常用场景

举几个例子:

网络通信服务,毫无疑问咯,网络的延迟是很不稳定的因素,乃至于传输文件,都是既耗时又占用资源的操作,其中有很多需要线程间的交互。这也是我们上一节为什么没有继续学习的原因。

数据库操作,这个就不需要我们多说了,用户界面中展示的数据来自于数据库的情况实在是太常见了,一般来说我们会提供用户操作数据库的几个方法,但是这些操作数据库的方法也许会比较耗时,比如大批量复制和排序,乃至于与网络通信结合,与云数据库通信。

多线程的限制

当然不是说:多线程实在是太厉害了,我们一定要多使用多线程,这样我们就能同时运行好多任务啦!实际上不是这样的,多线程优点很多,缺点也是存在的,

首先是占用内存,其次是太多线程会占用大量的处理器时间,会导致线程之间互相影响,都不会有太多的进度。

对于程序员来说,线程太多管理起来也是麻烦,还有可能产生许多bug。

线程的实现

Thread类

此类属于System.Threading命名空间下。

Thread 类 (System.Threading) | Microsoft Learn

属性:

ApartmentState	
已过时.
获取或设置此线程的单元状态。

CurrentCulture	
获取或设置当前线程的区域性。

CurrentPrincipal	
获取或设置线程的当前负责人(对基于角色的安全性而言)。

CurrentThread	
获取当前正在运行的线程。

CurrentUICulture	
获取或设置资源管理器使用的当前区域性以便在运行时查找区域性特定的资源。

ExecutionContext	
获取 ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息。

IsAlive	
获取指示当前线程的执行状态的值。

IsBackground	
获取或设置一个值,该值指示某个线程是否为后台线程。

IsThreadPoolThread	
获取指示线程是否属于托管线程池的值。

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

Name	
获取或设置线程的名称。

Priority	
获取或设置指示线程的调度优先级的值。

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

创建线程

构造函数

创建线程的构造函数有好几个,但是无一例外需要一个参数:委托,事实上就是告诉线程执行什么。其中传递的委托可以是ThreadStart的实例。

Thread(ParameterizedThreadStart)	
初始化 Thread 类的新实例,指定允许对象在线程启动时传递给线程的委托。

Thread(ParameterizedThreadStart, Int32)	
初始化 Thread 类的新实例,指定允许对象在线程启动时传递给线程的委托,并指定线程的最大堆栈大小。

Thread(ThreadStart)	
初始化 Thread 类的新实例。

Thread(ThreadStart, Int32)	
初始化 Thread 类的新实例,指定线程的最大堆栈大小。

举例:

下面就是初始化一个线程,然后启用它的例子。

public void serverstart()
{
    //开启服务端线程

    mywaitthread = new Thread(new ThreadStart(serverrun));
    mywaitthread.Start();
    tm_checkmessage1.Start();

}

释放线程

一般来说,我们创建的线程和系统自动给的线程一样,在执行完任务之后会自动释放。

但是如果线程具有循环的特性就需要我们给一个跳出循环的点。

或者是线程执行时间太长,我们需要手动释放。此时使用:

if (myclientthread != null)
{
    if (myclientthread.ThreadState == ThreadState.Running)
    {
        myclientthread.Abort();
    }
}

Abort方法可以引发结束线程的过程。一般来说这会导致线程的结束。

如此我们就知道怎么使用一个线程来执行我们预设的方法了,但是这是最简单的,也可以说是最好理解的多线程或者说不同于单线程的逻辑。

我们只是把我们程序从一条线,在某个节点,引出一条另外的线罢了。线程之间的交互,线程的状态我们都没有去详细解释。

明天会试图弄懂更多的程序执行的流程逻辑,尤其是:异步,同步这两个概念在很多面试官眼中的地位可以说很高很高的东西。


http://www.kler.cn/a/307219.html

相关文章:

  • 字节跳动Android面试题汇总及参考答案(80+面试题,持续更新)
  • 力扣104 : 二叉树最大深度
  • LabVIEW开发相机与显微镜自动对焦功能
  • mongoDB的安装及使用
  • DNS面临的4大类共计11小类安全风险及防御措施
  • webpack loader全解析,从入门到精通(10)
  • Python精选200Tips:121-125
  • Spring Boot集成Akka Cluster实现在分布式节点中执行任务
  • Android中如何处理运行时权限?
  • 02 信念·组织力·战略 - 目标管理
  • [OpenCV] 数字图像处理 C++ 学习——15像素重映射(cv::remap) 附完整代码
  • 数据中台建设(六)—— 数据资产管理
  • uniapp 携带网址跳转webview页面报错解决
  • tp6.0.8反序列化漏洞的一些看法
  • Redis详细解析
  • (c++)猜数字(含根据当前时间生成伪随机数代码)
  • C++ Primer Plus(速记版)-面向对象与泛型编程
  • 浅谈 React Fiber
  • 关于less的基本使用
  • 【 html+css 绚丽Loading 】000050 乾坤合璧轮
  • 常用 Git 命令
  • c++ #include <string> 介绍
  • Java 之 IO流
  • Java读取寄存器数据的方法
  • memo和useMemo的区别
  • Js中的pick函数