C#_事件_多线程(基础)

news2025/1/9 14:07:29

文章目录

    • 事件
      • 通过事件使用委托
    • 多线程(基础)
        • 进程:
        • 线程:
      • 多线程
        • 线程生命周期
        • 主线程
        • Thread 类中的属性和方法
        • 创建线程
        • 管理线程
        • 销毁线程
    • 昨天习题答案

事件

事件(Event)本质上来讲是一种特殊的多播委托,只能从声明它的类中进行调用,基本上说是一个用户操作,如按键、点击、鼠标移动等等,或者是一些提示信息,如系统生成的通知。应用程序需要在事件发生时响应事件。例如,中断。

通过事件使用委托

事件在类中声明且生成,且通过使用同一个类或其他类中的委托与事件处理程序关联。包含事件的类用于发布事件,这被称为 发布器(publisher) 类。其他接受该事件的类被称为 订阅器(subscriber) 类。事件使用 发布-订阅(publisher-subscriber) 模型。

发布器(publisher) 是一个包含事件和委托定义的对象。事件和委托之间的联系也定义在这个对象中。发布器(publisher)类的对象调用这个事件,并通知其他的对象。

订阅器(subscriber) 是一个接受事件并提供事件处理程序的对象。在发布器(publisher)类中的委托调用订阅器(subscriber)类中的方法(事件处理程序)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _06_事件
{
    internal class Program
    {
        static void Main(string[] args)
        {
            PublisherDome publisherDome=new PublisherDome();
            SubriberDome subscriberDome=new SubriberDome();

            publisherDome.MyEvent += new PublisherDome.Myentrust(subscriberDome.Print);

            publisherDome.SetValue("wuyifan");
        }
    }
    //定义一个发布器类
    public class PublisherDome
    {
        private string value;
        //在类的内部声明事件,首先必须先声明该事件的委托类型
        public delegate void Myentrust(string str);
        //基于上面的委托定义事件(当事件触发的时候,就会调用委托)
        public event Myentrust MyEvent;

        public void SetValue(string s)
        {
            value = s;
            MyEvent(value);
        }
       
    }
    //订阅器类
    public class SubriberDome
    {
        public void Print(string str)
        {
            Console.WriteLine(str);
        }
    }
}

//-----------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _07_事件
{
    internal class Program
    {
        static void Main(string[] args)
        {

            Son s=new Son();
            s.NoMenery += () =>
            {
                Console.WriteLine("爸爸知道了");
            };
            Console.WriteLine("按下回车就表示没钱了");
            Console.ReadLine();
            s.Buy();


        }
 
    }
  
       
    class Son
    {
        public delegate void NoMeneryDelegate();
        public event NoMeneryDelegate NoMenery;
        //一个买东西的方法
        public void Buy()
        {
            //只要买东西没钱了,就去执行委托
            NoMenery?.Invoke();
        }
    }
}

//-------------------------------


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _08_事件
{

    internal class Program
    {
        static Action fa;
        static void Main(string[] args)
        {
            Son s = new Son() {Name="亦凡" };
            Father f =new Father() {Name="亦凡的爸爸" };
            Mother m = new Mother() { Name = "亦凡的妈妈" };

            //创建爸爸给钱的事件
            fa = () =>
            {
                f.Buy(10);
                s.Money += 10;
                Console.WriteLine($"爸爸给了10块钱,现在还有{s.Money}");
                if (f.Money <= 0)
                {
                    s.OnNoMonery -= fa;
                }
            };

            s.OnNoMonery += fa;
            s.OnNoMonery += () =>
            {
                m.Buy(20);
                s.Money += 20;
                Console.WriteLine($"妈妈给了20块钱,现在还有{s.Money}");
            };

            s.Buy(3);
            s.Buy(3);
            s.Buy(20);
            s.Buy(20);
            s.Buy(20);
        }
    }
    class People
    {
        public string Name { get; set; }
        public int Money { get;set; }
        public virtual void Buy(int m)
        {
             Money -= m;
            Console.WriteLine($"{Name}花了{m}元,现在还有{Money}元");
        }

    }
    class Son : People
    {
        public Son() 
        {

            Money = 10;
         }

        //声明一个事件 当儿子没钱的时候触发
        public event Action OnNoMonery;

        public override void Buy(int m)
        {
            base.Buy(m);

            if (Money<=5)
            {
                OnNoMonery.Invoke();
            }

        }
    }
   class Father : People
    {
        public Father()
        {
            Money = 20;
        }
    }
    class Mother : People
    {
        public Mother()
        {
            Money = 200;
        }
    }


}
//----------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _09_事件
{

    internal class Program
    {
       
        static void Main(string[] args)
        {
            Son s = new Son() { Name = "亦凡" };
            Father f = new Father() { Name = "亦凡的爸爸" };
            Mother m = new Mother() { Name = "亦凡的妈妈" };

            s.OnNoMonery += m.SonNoMoney;
            s.OnNoMonery += f.SonNoMoney;

            s.Buy(3);
            s.Buy(3);
            s.Buy(20);
            s.Buy(20);
            s.Buy(20);
        }
    }
    class People
    {
        public string Name { get; set; }
        public int Money { get; set; }
        public virtual void Buy(int m)
        {
            Money -= m;
            Console.WriteLine($"{Name}花了{m}元,现在还有{Money}元");
        }

    }
    class Son : People
    {
        public Son()
        {

            Money = 10;
        }

        //声明一个事件 当儿子没钱的时候触发
        public event Action<Son> OnNoMonery;

        public override void Buy(int m)
        {
          

            if (Money <= m)
            {
                Console.WriteLine("钱不够,去要钱");
                OnNoMonery.Invoke(this);
              
            }
            base.Buy(m);
            if (Money<=5)
            {
                OnNoMonery.Invoke(this);
            }

        }
    }
    class Father : People
    {
        public Father()
        {
            Money = 20;
        }
        //儿子没钱执行的方法
        public void SonNoMoney(Son s)
        {
            Buy(10);
            s.Money+= 10;
            Console.WriteLine($"爸爸给了10块钱,现在还有{s.Money}");
            if (Money <= 0)
            {
                Console.WriteLine($"{Name}没钱了");
                s.OnNoMonery -= SonNoMoney;
            }
        }
    }
    class Mother : People
    {
        public Mother()
        {
            Money = 200;
        }
        public void SonNoMoney(Son s)
        {
            Buy(20);
            s.Money += 20;
            Console.WriteLine($"爸爸给了10块钱,现在还有{s.Money}");
        }
    }
}

多线程(基础)

进程:

进程并不是物理的东西,是虚拟出来的,是一种概念。当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。而一个进程又是由多个线程所组成的。是一种计算机概念,是程序在运行的时候,记录当前程序对计算机的各种资源的消耗。

线程:

线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数。也是一种计算机概念,线程是进程在响应操作的时候一个最小的单元,也包括CPU/硬盘/内存等。

在这里插入图片描述

多线程

多线程就是多个线程同时工作的过程,我们可以将线程看作是程序的执行路径,每个线程都定义了一个独特的控制流,用来完成特定的任务。如果您的应用程序涉及到复杂且耗时的操作,那么使用多线程来执行是非常有益的。使用多线程可以节省 CPU 资源,同时提高应用程序的执行效率,例如现代操作系统对并发编程的实现就用到了多线程。到目前为止我们编写的示例程序都是单线程的应用程序,这样的应用程序一次只能执行一个任务。

线程生命周期

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

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

  • 未启动状态:当线程实例被创建但 Start 方法未被调用时的状况;
  • 就绪状态:当线程准备好运行并等待 CPU 周期时的状况;
  • 不可运行状态:下面的几种情况下线程是不可运行的:
    • 已经调用 Sleep 方法;
    • 已经调用 Wait 方法;
    • 通过 I/O 操作阻塞。
  • 死亡状态:当线程已完成执行或已中止时的状况。
主线程

在 C# 中,System.Threading.Thread 类用于处理线程,它允许在多线程应用程序中创建和访问各个线程。在多线程中执行的第一个线程称为主线程,当 C# 程序开始执行时,将自动创建主线程,而使用 Thread 类创建的线程则称为子线程,您可以使用 Thread 类的 CurrentThread 属性访问线程。

            Thread th =Thread.CurrentThread;
            th.Name = "主线程";
            Console.WriteLine(th.Name);
Thread 类中的属性和方法

下表列出了 Thread 类中一些常用的属性:

属性描述
CurrentContext获取线程正在执行的上下文
CurrentCulture获取或设置当前线程的区域性
CurrentPrincipal获取或设置线程的当前负责人(对基于角色的安全性而言)
CurrentThread获取当前正在运行的线程
CurrentUICulture获取或设置资源管理器使用的当前区域性以便在运行时查找区域性特定的资源
ExecutionContext获取一个 ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息
IsAlive获取当前线程的执行状态
IsBackground获取或设置一个值,该值表示某个线程是否为后台线程
IsThreadPoolThread获取线程是否属于托管线程池
ManagedThreadId获取当前托管线程的唯一标识符
Name获取或设置线程的名称
Priority获取或设置线程的调度优先级
ThreadState获取当前线程的状态

下表列出了 Thread 类的一些常用的方法:

方法名描述
public void Abort()在调用此方法的线程上引发 ThreadAbortException,以终止此线程
public static LocalDataStoreSlot AllocateDataSlot()在所有的线程上分配未命名的数据槽,为了获得更好的性能,请改用以 ThreadStaticAttribute 特性标记的字段
public static LocalDataStoreSlot AllocateNamedDataSlot(string name)在所有线程上分配已命名的数据槽,为了获得更好的性能,请改用以 ThreadStaticAttribute 特性标记的字段
public static void BeginCriticalRegion()通知主机执行将要进入一个代码区域,在该代码区域内线程中止或未经处理的异常的影响可能会危害应用程序域中的其他任务
public static void BeginThreadAffinity()通知主机托管代码将要执行依赖于当前物理操作系统线程的标识指令
public static void EndCriticalRegion()通知主机执行将要进入一个代码区域,在该代码区域内线程中止或未经处理的异常仅影响当前任务
public static void EndThreadAffinity()通知主机托管代码已执行完依赖于当前物理操作系统线程的标识指令
public static void FreeNamedDataSlot(string name)为进程中的所有线程消除名称与数据槽之间的关联。为了获得更好的性能,请改用以 ThreadStaticAttribute 特性标记的字段
public static Object GetData(LocalDataStoreSlot slot)检索当前线程中指定的值。为了获得更好的性能,请改用以 ThreadStaticAttribute 特性标记的字段
public static AppDomain GetDomain()返回当前线程运行的域
public static AppDomain GetDomainID()返回应用程序域的唯一标识符
public static LocalDataStoreSlot GetNamedDataSlot(string name)查找已命名的数据槽。为了获得更好的性能,请改用以 ThreadStaticAttribute 特性标记的字段
public void Interrupt()中断处于 WaitSleepJoin 状态的线程
public void Join()在继续执行标准的 COM 和 SendMessage 消息泵处理期间,阻塞调用线程,直到某个线程终止为止。此方法有不同的重载形式
public static void MemoryBarrier()按如下方式同步内存访问:执行当前线程的处理器在对指令重新排序时不能采用先执行 MemoryBarrier 调用之后的内存存取,再执行 MemoryBarrier 调用之前的内存存取的方式
public static void ResetAbort()取消为当前线程请求的 Abort
public static void SetData(LocalDataStoreSlot slot, Object data)在当前正在运行的线程上的指定槽中为此线程的当前域设置数据。为了获得更好的性能,请改用以 ThreadStaticAttribute 特性标记的字段
public void Start()开始一个线程
public static void Sleep(int millisecondsTimeout)让线程暂停一段时间
public static void SpinWait(int iterations)让线程等待一段时间,时间长短由 iterations 参数定义
public static byte VolatileRead(ref byte address) public static double VolatileRead(ref double address) public static int VolatileRead(ref int address) public static Object VolatileRead(ref Object address)读取字段值。无论处理器的数目或处理器缓存状态如何,该值都是由计算机处理器写入的最新值
public static void VolatileWrite(ref byte address, byte value) public static void VolatileWrite(ref double address, double value) public static void VolatileWrite(ref int address, int value) public static void VolatileWrite(ref Object address, Object value)立即向字段中写入一个值,并使该值对计算机中的所有处理器都可见
public static bool Yield()终止当前正在调用的线程并执行另一个准备运行的线程(由操作系统选择将要执行的另一个线程)
创建线程

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

  static void Main(string[] args)
        {

            ThreadStart childref = new ThreadStart(CallToChildThread);
            Console.WriteLine("在Main函数中创建子线程");
            Thread childThead = new Thread(childref);
            childThead.Start();

        }
        public static void CallToChildThread()
        {
            Console.WriteLine("执行子线程");
        }
管理线程

Thread 类提供了各种管理线程的方法,比如可以使用 sleep() 方法使线程在特定时间段内暂停,

      static void Main(string[] args)
        {

            ThreadStart childref = new ThreadStart(CallToChildThread);
            Console.WriteLine("在Main函数中创建子线程");
            Thread childThead = new Thread(childref);
            childThead.Start();

        }
        public static void CallToChildThread()
        {
            Console.WriteLine("执行子线程");
            Console.WriteLine("子线程暂停5秒");
            Thread.Sleep(5000);//毫秒
            Console.WriteLine("继续执行子线程");

        }
销毁线程

Thread 类中提供了 Abort() 方法用于销毁线程,Abort() 方法会抛出一个 threadabortexception 异常来中止线程,这个异常不能被捕获,

  static void Main(string[] args)
        {

            ThreadStart childref = new ThreadStart(CallToChildThread);
            Console.WriteLine("在Main函数中创建子线程");
            Thread childThead = new Thread(childref);
            childThead.Start();
            Thread.Sleep(2000);
            Console.WriteLine("在Main函数终止子线程");
            childThead.Abort();

        }
        public static void CallToChildThread()
        {

            try
            {
                Console.WriteLine("执行子线程");
                for (int i = 0; i <= 10; i++) {
                    Thread.Sleep(500);
                    Console.WriteLine(i);
                }

                Console.WriteLine("子线程执行完成");
            }
            catch (ThreadAbortException e)
            {

                Console.WriteLine("线程终止"+e);
            }
            finally
            {
                Console.WriteLine("无法捕获线程异常");
            }
        }


			    Console.WriteLine("执行子线程");
                for (int i = 0; i <= 10; i++) {
                    Thread.Sleep(500);
                    Console.WriteLine(i);
                }

                Console.WriteLine("子线程执行完成");
            }
            catch (ThreadAbortException e)
            {

                Console.WriteLine("线程终止"+e);
            }
            finally
            {
                Console.WriteLine("无法捕获线程异常");
            }
        }

昨天习题答案

  1. 模拟List

    MyList myList1 = new MyList();

    ​ myList1.Add(1);

    ​ myList1.Add(20);

  2. 自定义 ForEach FindIndex Find…

//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Text;
//using System.Threading.Tasks;
//delegate bool MyFunc<T>(T v);
//namespace _03_昨天
//{
//    internal class Program
//    {
//        static void Main(string[] args)
//        {
//            int[] ints = { 1,  3, 6 };
//            string[] strings = { "亦凡1", "亦凡2", "罗祥", "李迪" };
//            //根据传入的数组和方法,从前往后查询,返回第一个满足条件的数据
//            //Find的工作原理:循环该数组,并且每次循环调用传递的方法,并且将当前的数据通过参数传递到方法中,如果方法返回了true,则Find直接返回当前这个参数
//            //参数1:查询的数组
//            //参数2:一个函数,这个函数应该返回一个布尔值,表示当前数值是否满足条件
//            //如果数组中没有满足条件的数组,则返回该类型的默认值
//             int num=  MyArray.MyFind<int>(ints, FnEven);
//             Console.WriteLine(num);
//             string str = MyArray.MyFind(strings, FnWu);
//             Console.WriteLine(str);







//        }
//        public static bool FnEven(int v)
//        {
//            return v % 2 == 0;
//        }
//        public static bool FnWu(string v)
//        {
//            return v.StartsWith("吴");
//        }

//    }

//    class MyArray
//    {
//        public static T MyFind<T>(T[] arr, MyFunc<T> fn)
//        {
//            for (int i = 0; i < arr.Length; i++)
//            {
//                if (fn(arr[i]))
//                {
//                    return arr[i];
//                }
//            }
//            return default(T);
//        }
//    }
//}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//delegate bool MyFunc<T>(T v);
namespace _03_昨天
{
    internal class Program
    {
        static void Main(string[] args)
        {
            int[] ints = { 1, 3, 6 };
            string[] strings = { "亦凡1", "亦凡2", "志祥", "云迪" };
            //根据传入的数组和方法,从前往后查询,返回第一个满足条件的数据
            //Find的工作原理:循环该数组,并且每次循环调用传递的方法,并且将当前的数据通过参数传递到方法中,如果方法返回了true,则Find直接返回当前这个参数
            //参数1:查询的数组
            //参数2:一个函数,这个函数应该返回一个布尔值,表示当前数值是否满足条件
            //如果数组中没有满足条件的数组,则返回该类型的默认值
            int num = MyArray.MyFind(ints,v=>v%2==0);
            Console.WriteLine(num);
            string str = MyArray.MyFind(strings, FnWu);
            Console.WriteLine(str);
            MyArray.MyForEach(ints, (v,i) =>
            {
                Console.WriteLine($"v=={v}");
                Console.WriteLine($"i=={i}");
            });
        }
        public static bool FnEven(int v)
        {
            return v % 2 == 0;
        }
        public static bool FnWu(string v)
        {
            return v.StartsWith("吴");
        }

    }

    class MyArray
    {
        public static T MyFind<T>(T[] arr, Func<T,bool> fn)
        {
            for (int i = 0; i < arr.Length; i++)
            {
                if (fn(arr[i]))return arr[i];
            }
            return default(T);
        }
        public static void MyForEach<T>(T[]arr,Action<T,int> fn)
        {
            for (int i = 0; i < arr.Length; i++)
            {
                fn(arr[i],i);
            }
        }
    }
}

觉得本篇文章写的还不错可以点赞,收藏,关注。主页有21天速通C#教程欢迎订阅!!!

在这里插入图片描述

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

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

相关文章

【python从入门到精通】-- 第二战:注释和有关量的解释

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;python从入门到精通&#xff0c;魔法指针&#xff0c;进阶C&#xff0c;C语言&#xff0c;C语言题集&#xff0c;C语言实现游戏&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持创作博文…

体育赛事直播源码是什么?四种适用场景及盈利模式

体育直播系统源码是指已经编写好的程序代码&#xff0c;用于搭建体育赛事直播软件平台。由于源码已经开发&#xff0c;并且源码可以被复制并多次使用&#xff0c;不需要从头开始开发&#xff0c;只需根据需求进行适当的修改和定制&#xff0c;因此可以大大加快上线速度&#xf…

应用层协议 - HTTP

文章目录 目录 文章目录 前言 1 . 应用层概要 2. WWW 2.1 互联网的蓬勃发展 2.2 WWW基本概念 2.3 URI 3 . HTTP 3.1 工作过程 3.2 HTTP协议格式 3.3 HTTP请求 3.3.1 URL基本格式 3.3.2 认识方法 get方法 post方法 其他方法 3.3.2 认识请求报头 3.3.3 认识请…

36.网络游戏逆向分析与漏洞攻防-游戏网络通信数据解析-数据解码器的实现

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果 内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;35.登录成功数据…

2024年【安全员-C证】考试及安全员-C证考试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 安全员-C证考试根据新安全员-C证考试大纲要求&#xff0c;安全生产模拟考试一点通将安全员-C证模拟考试试题进行汇编&#xff0c;组成一套安全员-C证全真模拟考试试题&#xff0c;学员可通过安全员-C证考试题全真模拟…

Git基础(25):Cherry Pick合并指定commit id的提交

文章目录 前言指定commit id合并使用TortoiseGit执行cherry-pick命令 前言 开发中&#xff0c;我们会存在多个分支开发的情况&#xff0c;比如dev&#xff0c;test, prod分支&#xff0c;dev分支在开发新功能&#xff0c;prod作为生产分支已发布。如果某个时候&#xff0c;我们…

AGI争论燃爆!奥特曼、马斯克、杨立坤、Hinton一众大佬关于“AGI何时降临?”的讨论

随着Sora、Claude 3的亮相以及GPT-5的预告&#xff0c;一个激动人心的话题不断被提起&#xff1a;如果存在一种智能能够超越人类&#xff0c;那么世界将会变成什么样子&#xff1f; 更引人注目的问题是&#xff0c;我们究竟能在何时迎来这样的“超级AI”&#xff1f; GPT-3.5…

Hudi部署

目录 前言 Hudi的介绍 一、Hudi是什么&#xff1f; 二、Hudi的特点功能和优势 三、Hudi的使用场景 Hudi的搭建部署 一、准备 二、搭建 1&#xff09;搭建JAVA环境和Hadoop环境 2&#xff09;部署zookeeper 3&#xff09;部署Spark on yarn 4&#xff09;部署maven环…

Avalonia11.0.2+.Net6.0支持多语言,国际化

Avalonia11.0.2+.Net6.0支持多语言,国际化 操作系统项目结构最终效果具体实现安装Prism.Avalonia准备多语言文件语言资源加载类界面标记扩展类界面中使用国际化VM具体实现VM里面使用多语言方法操作系统 项目结构 最

【前端Vue】Vue3+Pinia小兔鲜电商项目第3篇:静态结构搭建和分类实现,1. 整体结构创建【附代码文档】

Vue3ElementPlusPinia开发小兔鲜电商项目完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;认识Vue3&#xff0c;使用create-vue搭建Vue3项目1. Vue3组合式API体验,2. Vue3更多的优势,1. 认识create-vue,2. 使用create-vue创建项目,1. setup选项的写法和执行…

007 日期类型相关工具类

推荐一篇文章 http://t.csdnimg.cn/72F7Jhttp://t.csdnimg.cn/72F7J

【TB作品】430单片机,单片机串口多功能通信,Proteus仿真

文章目录 题目功能仿真图程序介绍代码、仿真、原理图、PCB 题目 60、单片机串口多功能通信 基本要求: 设计一串口通信程序,波特率38400,通过RS232与PC机通信。 自动循环发送数据串(设计在程序中) 接收并存储和显示该数据串 在发送端定义10个ASCII码键0-9 按键发送单字节,PC机接…

uboot - pinctrl - FPGA回片前测试阶段 - 设置GPIO引脚复用失败

问题描述 pinctrl设置引脚复用失败&#xff0c;没有调用到controller中的set_groups_function函数。 问题定位 pinctrl如何注册dm节点如何进行设备树中各个设备节点下的复用配置为什么没调用到控制器实现的set_groups_function函数 &gpio0 {status "okay";p…

数据结构进阶篇 之 【二叉树】详细概念讲解(带你认识何为二叉树及其性质)

有朋自远方来&#xff0c;必先苦其心志&#xff0c;劳其筋骨&#xff0c;饿其体肤&#xff0c;空乏其身&#xff0c;鞭数十&#xff0c;驱之别院 一、二叉树 1、二叉树的概念 1.1 二叉树中组分构成名词概念 1.2 二叉树的结构概念 1.3 特殊的二叉树 2、二叉树的存储结构 …

c语言--实用调试技巧

1什么是bug 2调试是什么&#xff0c;有多重要&#xff1f; 3debug与release 4windows环境调试简绍 5一些调试的实例 6如何写出好的代码&#xff08;便于调试&#xff09; 7编程常见错误 1什么是bug 导致计算机出现问题就叫bug 2调试是什么&#xff0c;有多重要&#x…

4.线性数据结构——1.vector弥补数组的缺陷及其底层逻辑

数组的缺陷 数组在定义时大小固定&#xff0c;不能改变如果要定义在main内部&#xff0c;数组大小不能超过一百万&#xff08;6个0&#xff09;&#xff0c;超过需要定义为全局变量 定义在main内部&#xff0c;数组创建在内存的栈中&#xff0c;作为局部变量&#xff0c;但栈的…

基于stm32与TJC3224T124_011串口屏的PID调参器(附完整工程)

电赛在即&#xff0c;每次比赛调PID都是一件比较繁琐的事。每次都要在程序中改完再烧录到板子上&#xff0c;特别耗时。正好最近发现实验室的一块串口屏比较好玩。 于是就做了这个调PID的东西。它可以通过串口直接修改PID的值&#xff0c;从而达到快速调PID的目的。下面我将完整…

c++初阶------c++代码模块

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

MATLAB 公共区域的点云合并(46)

MATLAB 公共区域的点云合并(46) 一、算法介绍二、算法实现1.代码2.效果一、算法介绍 点云配准后,或者公共区域存在多片点云对场景进行冗余过量表达时,我们需要将点云进行合并,Matlab点云工具中提供了这样的合并函数,通过指定网格步长,对初始点云进行过滤。 函数主要实…

[STL]priority_queue类及反向迭代器的模拟实现

&#x1fa90;&#x1fa90;&#x1fa90;欢迎来到程序员餐厅&#x1f4ab;&#x1f4ab;&#x1f4ab; 今日主菜&#xff1a; priority_queue类及反向迭代器 主厨&#xff1a;邪王真眼 主厨的主页&#xff1a;Chef‘s blog 所属专栏&#xff1a;c大冒险 向着c&…