C#多线程开发详解
C#多线程开发详解
- 持续更新中。。。。。
- 一、为什么要使用多线程开发
- 1.提高性能
- 2.响应性
- 3.资源利用
- 4.任务分解
- 5.并行计算
- 6.实时处理
- 二、多线程开发缺点
- 1.竞态条件
- 2.死锁和饥饿
- 3.调试复杂性
- 4.上下文切换开销
- 5.线程安全性
- 三、多线程开发涉及的相关概念
- 常用概念
- (1)lock
- (2)查看当前工作线程信息
- (3)主线程、前台线程、后台线程
- 1.Thread(线程)
- (1)创建线程
- (2) 线程同步
- (3)线程异步
- 2.ThreadPool(线程池)
- 3.Task(任务)
- (1)Task与Thead的关系
- 4.Task Parallel Library (TPL)(任务并行库)
- 5.Async/Await(异步/等待)
- 6.Monitor(监视器)
- 7.Semaphore(信号量)
- 8.SemaphoreSlim
- 9.AutoResetEvent(自动复位事件)
- 10.ManualResetEvent(手动复位事件)
- 11.CancellationToken(取消标记)
- 12.volatile(易失性修饰符)
- 13.Mutex(互斥锁)
- 14.ReaderWriterLock(读写锁)
- 15.ReaderWriterLockSlim(轻量级读写锁)
- 16.SpinLock
- 17.SpinWait
- 18.Barrier(屏障)
- 四、多线程的异常捕获问题
持续更新中。。。。。
一、为什么要使用多线程开发
1.提高性能
多线程允许程序同时执行多个任务,从而有效利用多核处理器,加快程序的执行速度。特别是在需要处理大量计算、I/O 操作或并行任务的应用中,多线程可以显著提高性能。
2.响应性
多线程使应用能够同时处理多个用户请求或事件,提高了应用的响应性。例如,多线程可以保持用户界面的响应,即使在执行长时间操作时也能让用户继续交互。
3.资源利用
多线程可以更有效地利用系统资源,如内存和网络连接。这对于高并发服务器、网络应用和数据处理任务特别有用。
4.任务分解
将复杂任务分解为多个小任务,每个任务在不同的线程中执行,可以简化问题并提高可维护性。
5.并行计算
多线程可以用于并行计算,例如在科学计算、数据分析和图像处理领域。这有助于加速大规模计算。
6.实时处理
在实时系统中,多线程可以保证任务在规定的时间内完成,从而满足对时间敏感性的需求。
二、多线程开发缺点
1.竞态条件
多线程可能会导致竞态条件,即多个线程竞争访问共享资源,可能导致数据不一致性和错误。
2.死锁和饥饿
不正确的线程同步可能导致死锁(多个线程无法继续执行)或饥饿(某些线程无法获取所需资源)问题。
3.调试复杂性
多线程程序的调试和错误跟踪可能会更加复杂,因为线程间的交互和排错可能变得更难。
4.上下文切换开销
上下文切换(Context Switching)是多线程环境中的一种操作,指的是在一个 CPU 核心上切换正在执行的线程,从当前线程的执行上下文(包括寄存器状态、程序计数器等)切换到另一个线程的执行上下文, 线程的切换需要额外的开销,因此在某些情况下,过多的线程可能会导致性能下降。
- 当一个线程的时间片(时间片轮转调度算法)用完,操作系统需要挂起该线程并切换到另一个线程。
- 当一个线程主动放弃 CPU,例如通过调用 Thread.Sleep()、Thread.Yield() 或等待某个事件时
3.当一个线程被高优先级的线程抢占
上下文切换的过程涉及以下步骤:
- 保存当前线程的上下文: 操作系统将当前线程的寄存器状态、程序计数器等信息保存到该线程的内存空间中,以便稍后能够恢复该线程的执行
2.恢复目标线程的上下文: 操作系统从目标线程的内存空间中恢复寄存器状态、程序计数器等信息,准备让目标线程继续执行。- 切换内核堆栈: 每个线程都有自己的内核堆栈,上下文切换时,操作系统会切换内核堆栈,以确保线程的隔离性。
上下文切换开销指的是从一个线程切换到另一个线程的过程中所涉及的时间和资源开销。这些开销主要包括以下几个方面:
- 寄存器保存和恢复: 当线程切换时,操作系统需要保存当前线程的寄存器状态,然后恢复目标线程的寄存器状态。这涉及到大量的数据拷贝和计算。
2.内存访问: 上下文切换过程中需要频繁访问内存,包括将寄存器状态和其他上下文信息写入内存,以及从内存中读取目标线程的上下文信息。
3.调度开销: 操作系统需要决定要切换到哪个线程,这涉及到调度算法的开销,包括选择合适的线程并进行必要的线程队列操作。
4.TLB(Translation Lookaside Buffer)失效: 当线程切换时,虚拟内存的映射可能会发生变化,导致 TLB 缓存失效,从而增加了内存访问的开销。
上下文切换开销会影响系统的整体性能,特别是在高并发、频繁切换的情况下。因此,在设计多线程应用程序时,需要考虑如何减少上下文切换的发生,以提高程序的执行效率。一些方法包括:
- 使用线程池:线程池可以减少线程的创建和销毁,从而减少上下文切换的频率。
- 合理设置线程数量:避免创建过多线程,以减少不必要的上下文切换。
3.使用异步编程模型:使用异步操作和任务可以减少线程的使用,从而减少上下文切换。
5.线程安全性
多线程编程需要谨慎处理线程安全性,以避免数据竞争和共享资源的冲突。
三、多线程开发涉及的相关概念
常用概念
(1)lock
在 C# 中,lock 关键字用于实现线程同步,以确保在多线程环境中对共享资源的访问是安全的。lock 关键字会创建一个互斥锁(也称为监视器锁),只有一个线程可以获得该锁,从而确保在同一时间只有一个线程能够执行被 lock 包围的代码块。
lock (lockObject)
{// 在这里执行需要同步的代码
}
其中,lockObject 是一个用于同步的对象。它可以是任何引用类型的对象,但通常是一个专门用于同步的对象。多个线程可以共享同一个 lockObject,并且只有一个线程能够获得锁并执行被 lock 包围的代码块。
class Program
{static readonly object lockObject = new object(); // 同步对象static void Main(string[] args){for (int i = 0; i < 5; i++){ThreadStart start = () =>{lock (lockObject){Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} is in the critical section.");Thread.Sleep(1000);Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} has exited the critical section.");}};Thread thread = new Thread(start);thread.Start();}Console.ReadKey();}
}
(2)查看当前工作线程信息
可以使用 Thread.CurrentThread 属性来获取当前正在执行的线程的信息。这个属性返回一个表示当前线程的 Thread 对象,你可以使用它来查询线程的各种属性和状态。
Thread 类还提供了 Priority 属性,允许你设置线程的优先级。然而,操作系统不一定会完全遵循线程的优先级,这取决于操作系统的调度机制。
线程可以分为前台线程和后台线程。前台线程是主线程的一部分,如果所有前台线程都完成,程序将终止。后台线程是在后台运行的线程,如果所有前台线程都完成,程序会立即终止,不会等待后台线程完成。
using System;
using System.Threading;class Program
{static void Main(){Thread currentThread = Thread.CurrentThread;Console.WriteLine($"Thread ID: {currentThread.ManagedThreadId}");Console.WriteLine($"Thread Name: {currentThread.Name}");Console.WriteLine($"Is Thread Background: {currentThread.IsBackground}");Console.WriteLine($"Thread Priority: {currentThread.Priority}");Console.WriteLine($"Thread State: {currentThread.ThreadState}");}
}
(3)主线程、前台线程、后台线程
主线程(Main Thread),它是程序的入口点,并且在程序启动时自动创建。主线程负责启动其他线程,并且通常是其他线程的父线程,但并不是所有线程都是主线程的子线程。
线程之间没有严格的父子关系。主线程和其他线程之间通常是平等的,没有直接的父子关系。但是,你可以通过编程来模拟一种线程间的层次关系,使得某些线程在逻辑上看起来是其他线程的子线程。这通常涉及线程的创建、协调和通信
以下是一个示例,演示了如何通过逻辑上的组织来模拟一种主线程和子线程的关系:
using System;
using System.Threading;class Program
{static void Main(){Console.WriteLine("Main thread starts.");Thread parentThread = new Thread(ParentThreadMethod);parentThread.Start();parentThread.Join();Console.WriteLine("Main thread ends.");}static void ParentThreadMethod(){Console.WriteLine("Parent thread starts.");Thread childThread = new Thread(ChildThreadMethod);childThread.Start();childThread.Join();Console.WriteLine("Parent thread ends.");}static void ChildThreadMethod(){Console.WriteLine("Child thread starts.");Thread.Sleep(2000);Console.WriteLine("Child thread ends.");}
}
前台线程(Foreground Threads):
这些线程是由主线程或其他前台线程创建的,它们的生命周期独立于主线程,但它们不是主线程的子线程。前台线程与主线程之间的关系是平级的。当所有前台线程都执行完毕时,程序才会退出,无论主线程是否结束。
- 生命周期:
前台线程的生命周期不受其他线程的影响。即使主线程退出,前台线程仍然可以继续执行,直到完成。- 程序退出:
如果程序中还有前台线程在运行,主程序将等待所有前台线程完成后才会退出。主线程也是前台线程,如果主线程退出,会等待其他前台线程完成后再退出。- 影响程序:
前台线程会阻塞程序的退出,直到所有前台线程完成。这可能会影响程序的退出速度。- 默认类型:
== 通过 new Thread(…) 创建的线程默认是前台线程。==
后台线程(Background Threads):
这些线程也是由主线程或其他前台线程创建的,它们同样是平级的,不是主线程的子线程。后台线程与主线程之间的关系也是平级的。当所有前台线程结束,程序会退出,同时会终止所有后台线程,不管后台线程是否执行完毕。
- 生命周期:
后台线程的生命周期受到主线程的影响。如果所有前台线程(包括主线程)都已经完成,程序会立即退出,同时终止后台线程,不管后台线程是否执行完毕。- 程序退出:
如果程序中只剩下后台线程在运行,即使主线程结束,程序也会立即退出,不会等待后台线程完成。- 影响程序:
后台线程不会阻塞程序的退出,它们对程序的退出速度没有影响。- 设置后台线程:
可以通过设置线程的 IsBackground 属性为 true 将线程设置为后台线程。通过 Thread 类创建的线程可以使用这个属性进行设置。
使用场景:
- 前台线程通常用于执行一些关键任务,确保这些任务的完成。例如,在主线程需要等待其他线程的结果时,可以使用前台线程。
- 后台线程通常用于执行一些非关键性的任务,如日志记录、监控等。它们不会阻止程序的退出,适用于在程序退出时不需要保证任务完全执行的情况。
错误使用后台线程,可能引起资源泄露或意外行为
- 资源泄露:
如果后台线程在程序退出时还在执行,可能会导致资源无法正确释放。例如,如果后台线程打开了文件、网络连接或其他资源,但程序退出时这些资源没有被正确关闭,就会发生资源泄露。- 不完整的操作:
如果后台线程执行一些需要完整执行的操作,例如数据的写入、状态的更新等,但程序退出时这些操作未完成,可能会导致数据不一致或损坏。- 异常处理:
后台线程的异常不会被捕获并传播到主线程,可能会导致未处理的异常,影响程序的稳定性。
4.线程同步:
在程序退出时,后台线程可能还在等待某些同步操作完成,但这些操作可能无法在后台线程终止之前完成,可能会导致死锁或其他线程同步问题。
1.Thread(线程)
表示一个执行线程,用于并行执行代码。可以使用 Thread 类来创建和管理线程。线程是执行程序的最小单位,多线程编程允许程序同时执行多个任务,从而提高性能和响应性。
Thread 类是 C# 中用于线程操作的基础类之一。然而,对于更高级的线程编程需求,你可能会使用 Task、ThreadPool、异步编程模型等更高级的机制,以便更好地管理和协调多线程操作。
Thead常用方法
- Start(): 启动线程,使其开始执行指定的方法。
- Join(): 阻塞当前线程,直到目标线程完成。
- Abort(): 强制终止线程的执行。不建议使用,因为可能导致资源泄漏或不稳定的状态。
- Sleep(int millisecondsTimeout): 使当前线程休眠指定的毫秒数。
- IsAlive(): 返回一个布尔值,指示线程是否处于活动状态。
- Interrupt(): 中断线程,引发一个 ThreadInterruptedException 异常。
- Suspend() 和 Resume(): 已过时,不推荐使用。用于暂停和恢复线程的执行。
- GetDomain() 和 GetDomainID(): 获取线程所属的应用程序域和域标识符。
- SetApartmentState(ApartmentState state): 设置线程的单元状态,用于控制线程的COM互操作行为。
- GetCurrentThreadId() 和 GetDomainID(): 获取当前线程的唯一标识符。
- Interrupt(): 中断线程的等待状态,引发 ThreadInterruptedException 异常。
- Yield(): 提示系统允许其他等待线程运行。
- Name 和 CurrentThread.Name: 获取或设置线程的名称。
- SetData 和 GetData: 在线程范围内设置和获取线程本地存储数据。
- Start(ParameterizedThreadStart) 和 Start(ParameterizedThreadStart, Object): 启动线程并传递参数给线程方法。
- TrySetApartmentState(ApartmentState): 尝试设置线程的单元状态,返回是否成功。
- StartNew(Action) 和 StartNew(Action, CancellationToken): 使用 Task 类来启动线程。
这些方法提供了各种线程管理和操作的能力。然而,需要注意,一些方法已经过时,不推荐使用,而且一些方法可能会涉及多线程编程的复杂性,需要谨慎使用。在编写多线程应用程序时,确保仔细阅读文档并根据需求选择适当的方法。
(1)创建线程
通常,你需要传递一个方法作为线程的入口点,然后调用 Start 方法来启动线程。
using System;
using System.Threading;class Program
{static void Main(){Thread thread = new Thread(WorkerMethod);thread.Start(); // 启动线程}static void WorkerMethod(){Console.WriteLine("Thread is running.");}
}
(2) 线程同步
在多线程环境中,线程同步是一种确保多个线程协调工作的机制。Thread 类提供了 Join 方法,允许一个线程等待另一个线程完成。这在需要等待某个线程的结果时特别有用。
using System;
using System.Threading;class Program
{static void Main(){Thread currentThread = Thread.CurrentThread;Console.WriteLine($"Thread ID: {currentThread.ManagedThreadId}");Thread thread = new Thread(WorkerMethod);thread.Start();// 主线程等待子线程完成thread.Join();Console.WriteLine("Thread has finished.");}static void WorkerMethod(){Thread currentThread = Thread.CurrentThread;Console.WriteLine($"Thread ID: {currentThread.ManagedThreadId}");Console.WriteLine("Thread is running.");Thread.Sleep(2000); // 模拟耗时操作}
}
(3)线程异步
using System;
using System.Threading;class Program
{static void Main(){Thread currentThread = Thread.CurrentThread;Console.WriteLine($"Thread ID: {currentThread.ManagedThreadId}");Thread thread = new Thread(WorkerMethod);thread.Start();// 主线程等待子线程完成//thread.Join();Console.WriteLine("Thread has finished.");//这里子线程虽然还没有处理完,但是直接返回了,没有继续等待子线程,但是子线程还在继续处理工作,没有出现阻塞现象return "ok";}static void WorkerMethod(){Thread currentThread = Thread.CurrentThread;Console.WriteLine($"Thread ID: {currentThread.ManagedThreadId}");Console.WriteLine("Thread is running.");Thread.Sleep(10000); // 模拟耗时操作//这里在主线程结束后,继续在处理10s后打印Thread is WordEnd;Console.WriteLine("Thread is WordEnd.");}
}
可以思考下,主线程返回成功了,但是子线程执行失败了,这可怎么办?
2.ThreadPool(线程池)
是一个用于管理和重用线程的机制,可以使用 ThreadPool 类来执行异步任务。
3.Task(任务)
表示一个异步操作,可以使用 Task 类或 Task.Run 方法来创建和管理任务。
(1)Task与Thead的关系
4.Task Parallel Library (TPL)(任务并行库)
是 C# 中用于并行编程的高级库,用于处理异步和并行操作,包括数据并行和任务并行。
5.Async/Await(异步/等待)
是 C# 5.0 引入的异步编程模型,用于创建和管理异步方法和操作。
6.Monitor(监视器)
是用于实现线程同步的一种机制,用于保护共享资源,避免竞态条件。可以使用 Monitor 类或 lock 关键字来实现。
首先lock和Minitor有什么区别呢?
其实lock在IL代码中会被翻译成Monitor。也就是Monitor.Enter(obj)和Monitor.Exit(obj).
lock(obj)
{}//等价为:
try{ Monitor.Enter(obj)
}catch()
{}
finally
{Monitor.Exit(obj)
}
7.Semaphore(信号量)
用于控制并发访问资源的数量,可以使用 Semaphore 类来创建和管理信号量。
8.SemaphoreSlim
是 Semaphore 的改进版本,提供更好的性能和可伸缩性。
9.AutoResetEvent(自动复位事件)
用于线程同步,允许一个线程等待另一个线程发出信号。
10.ManualResetEvent(手动复位事件)
用于线程同步,允许一个线程等待多个线程发出信号。
11.CancellationToken(取消标记)
用于在异步操作中请求取消操作,可以在异步方法中传递给取消标记。
12.volatile(易失性修饰符)
用于标记字段,指示编译器不应该对标记字段进行优化,以确保多线程环境下的正确性。
13.Mutex(互斥锁)
是一种用于实现线程同步的机制,用于保护共享资源,防止多个线程同时访问。
14.ReaderWriterLock(读写锁)
允许多个线程同时读取共享资源,但只允许一个线程写入资源。适用于读操作频繁、写操作较少的场景。
15.ReaderWriterLockSlim(轻量级读写锁)
是 ReaderWriterLock 的改进版本,提供更好的性能和可伸缩性。
16.SpinLock
是一种自旋锁,用于短时间内的临界区保护。它使用忙等待来尝试获取锁,适用于临界区很小的情况。
17.SpinWait
用于在自旋等待期间执行自旋操作,可以根据不同的条件进行自旋。
18.Barrier(屏障)
允许多个线程在一个点上等待,直到所有线程都达到该点。适用于需要所有线程协调同步的场景。
四、多线程的异常捕获问题
相关文章
相关文章:

C#多线程开发详解
C#多线程开发详解 持续更新中。。。。。一、为什么要使用多线程开发1.提高性能2.响应性3.资源利用4.任务分解5.并行计算6.实时处理 二、多线程开发缺点1.竞态条件2.死锁和饥饿3.调试复杂性4.上下文切换开销5.线程安全性 三、多线程开发涉及的相关概念常用概念(1)lock(2)查看当前…...

Linux 基础篇(六)sudo和添加信任用户
一、sudo 1.是什么? 给被信任的普通用户授权,让被信任的普通用户能执行root用户才能执行的命令的一个命令。 2.为什么? 很多时候我们要在被信任的普通用户下执行一些root用户才能执行的命令,如 yum… 所以需要有一个命令能给普通用…...

【Linux】程序地址空间
程序地址空间 首先引入地址空间的作用什么是地址空间为什么要有地址空间 首先引入地址空间的作用 1 #include <stdio.h>2 #include <unistd.h>3 #include <stdlib.h>4 int g_val 100;6 int main()7 {8 pid_t id fork();9 if(id 0)10 {11 int cn…...

springboot 设置自定义启动banner背景图 教程
springboot banner Spring Boot中的banner是在应用程序启动时显示的一个ASCII艺术字符或文本。它被用来给用户展示一些关于应用程序的信息,例如名称、版本号或者公司标志等。 使用Spring Boot的默认设置,如果项目中有一个名为“banner.txt”的文件放置…...

CSS的引入方式有哪些?
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 内联样式(Inline Styles)⭐ 内部样式表(Internal Stylesheet)⭐ 外部样式表(External Stylesheet)⭐ 导入样式表(Import Stylesheet)⭐ 写在最…...

.net core的Knife4jUI,让swagger更精致
要在 .NET Core 中使用 IGeekFan.AspNetCore.Knife4jUI,您可以按照以下步骤进行配置: 首先,安装 IGeekFan.AspNetCore.Knife4jUI NuGet 包。可以通过 Visual Studio 的 NuGet 包管理器或者 .NET CLI 进行安装。 在 Startup.cs 文件的 Config…...
Android 开发中需要了解的 Gradle 知识
作者:wkxjc Gradle 是一个基于 Groovy 的构建工具,用于构建 Android 应用程序。在 Android 开发中,了解 Gradle 是非常重要的,因为它是 Android Studio 默认的构建工具,可以帮助我们管理依赖项、构建应用程序、运行测试…...

Linux之【进程间通信(IPC)】-总结篇
Linux之【进程间通信(IPC)】-总结篇 管道System V共享内存System V消息队列System V信号量IPC资源的管理方式 往期文章 1.进程间通信之管道 2.进程间通信之System V共享内存 管道 进程之间具有独立性,拥有自己的虚拟地址空间,因…...

C++QT教程3——手册4.11.1自带教程(笔记)——创建一个基于Qt Widget的应用程序
文章目录 创建一个基于Qt Widget的应用程序创建Text Finder项目素材文件 填补缺失的部分设计用户界面完成头文件完成源文件创建资源文件 编译和运行程序 参考文章 创建一个基于Qt Widget的应用程序 本教程介绍如何使用Qt Creator创建一个小型Qt应用程序,名为Text F…...

手机商城网站的分析与设计(论文+源码)_kaic
目录 摘 要 1 1 绪论 2 1.1选题背景意义 2 1.2国内外研究现状 2 1.2.1国内研究现状 2 1.2.2国外研究现状 3 1.3研究内容 3 2 网上手机商城网站相关技术 4 2.1.NET框架 4 2.2Access数据库 4 2.3 JavaScript技术 4 3网上手机商城网站分析与设…...

vue2 封装 webSocket 开箱即用
第一步: 下载 webSocket npm install vue-native-websocket --save 第二步: 需要在 main.js 中 引入 import websocket from vue-native-websocket; Vue.use(websocket, , {connectManually: true, // 手动连接format: json, // json格式reconnection:…...

使用fopen等标准C库来操作文件
fopen 需要的头文件: #include <stdio.h> 函数原型: FILE *fopen(const char *pathname, const char *mode); 参数: pathname: 文件路径mode: “r” :以只读方式打开文件,该文件必须存在。“w” ÿ…...
Spring-Cloud-Loadblancer详细分析_1
背景 从SpringCloud 2020 版本之后,组件移除了除 Eureka 以外,所有 Netflix 的相关,包括最常用的 Ribbon Hystrix 等,所以 SpringCloud 在 spring-cloud-commons 提供了Loadbalancer 用来替代 Ribbon。本系列就来介绍Loadbalance…...
键盘键码keyCode对照表
字母和数字键的键码值(KeyCode)按键键码按键键码A65J74B66K75C67L76D68M77E69N78F70O79G71P80H72Q81I73R82 字母和数字键的键码值(KeyCode)按键键码按键键码S83149T84250U85351V86452W87553X88654Y89755Z90856048957 数字键盘上的键的键码值(KeyCode)按键键码按键键码0968104…...

jupyter切换conda虚拟环境
环境安装 conda install nb_conda 进入你想使用的虚拟环境: conda activate your_env_name 在你想使用的conda虚拟环境中: conda install -y jupyter 在虚拟环境中安装jupyter: conda install -y jupyter 重启jupyter 此时我们已经把该安装…...
【数据结构•堆】经典问题:k路归并
题目描述 k路归并问题: 把k个有序表合并成一个有序表。( k < 10^4 ) 输入输出格式 输入格式: 输入数据共有 2*k1 行。 第一行,一个整数k( k < 10^4 ),表示有k个有序…...
VUE3 动态路由
带参数的动态路由匹配 很多时候,我们需要将给定匹配模式的路由映射到同一个组件。例如,我们可能有一个 User 组件,它应该对所有用户进行渲染,但用户 ID 不同。在 Vue Router 中,我们可以在路径中使用一个动态字段来实现…...

CentOS软件包管理rpm、yum
一、软件包概述 Linux常见软件包分为两种,分别是源代码包、二进制文件包。源代码包是没有经过编译的包,需要经过GCC、C编译器编译才能运行,文件内容包含源代码文件,通常以.tar.gz、.zip、.rar结尾;二进制包无需编译&am…...

【VSCode】报错:出现段错误解决办法 (Segmentation fault)
VScode报错:Segmentation fault (core dumped)的解决办法 解决Program received signal SIGSEGV, Segmentation fault.的辛酸 Linux环境下段错误的产生原因及调试方法小结 Linux下的段错误Segmentationfault产生的原因及调试方法经典.pdf 在程序中,TF…...
Linux Centos 8 用户管理之重置密码
如果在使用linux系统时遇到系统密码问题无法进入系统或者操作的时候可以按照下面的方法重置用户密码。 一、root用户密码重置: 方式一: 1.重启电脑或虚拟机,在刚进引导界面时候按“e"键,进入编辑模式。 2.在”quiet"…...

wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...

铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...