《C++多线程下单例 “锁钥” 法则》
一、概述
本文章介绍了一段 C++ 代码,该代码实现了在多线程环境下的单例模式。单例模式确保一个类只有一个实例,并提供全局访问点。在多线程场景中,需要额外的同步机制来保证单例对象创建的线程安全性。单例模式在许多场景中都有重要应用,比如资源管理、配置管理等,它能有效避免资源的重复创建和不一致问题。
二、代码结构与功能模块
(一)Mutex 类
-
功能:封装了 POSIX 线程库(pthread)中的互斥锁操作,用于实现线程同步。互斥锁是多线程编程中常用的同步工具,它可以保证在同一时刻只有一个线程能够访问被保护的临界区代码,防止数据竞争和不一致问题。
-
成员变量:
-
pthread_mutex_t m
:用于表示互斥锁的内部变量。pthread_mutex_t
是 POSIX 线程库中定义的互斥锁类型,通过这个变量来存储和管理互斥锁的状态。
-
-
成员函数:
-
Mutex()
:构造函数,调用pthread_mutex_init(&m, 0)
初始化互斥锁。在对象创建时,通过这个函数对互斥锁进行初始化操作,为后续的加锁和解锁操作做准备。其中pthread_mutex_init
函数的第一个参数是指向要初始化的互斥锁变量的指针,第二个参数是一个指向属性对象的指针,这里传递0
表示使用默认属性。 -
void lock()
:加锁函数,调用pthread_mutex_lock(&m)
对互斥锁进行加锁操作,阻止其他线程同时访问受保护的资源。当一个线程调用这个函数时,如果互斥锁当前处于未锁定状态,那么该线程将获得锁并继续执行;如果互斥锁已经被其他线程锁定,那么当前线程将被阻塞,直到获得锁为止。 -
void unlock()
:解锁函数,调用pthread_mutex_unlock(&m)
释放互斥锁,允许其他等待的线程获取锁并访问资源。当一个线程完成对临界区代码的操作后,需要调用这个函数释放互斥锁,以便其他被阻塞的线程有机会获取锁并继续执行。
(二)singleton 类
-
功能:实现单例模式,确保只有一个该类的实例存在,并提供获取该实例的静态方法。单例模式的核心目的是保证在整个应用程序中,一个类只有一个实例,并且可以通过一个全局的访问点来获取这个实例。
-
成员变量:
-
static singleton* only
:静态指针,用于存储唯一的单例对象实例,初始化为NULL
。这个指针在整个程序运行期间保持对单例对象的引用,通过它来实现对单例对象的唯一访问。 -
static Mutex m
:静态互斥锁对象,用于在多线程创建单例对象时进行同步。由于在多线程环境下,可能会有多个线程同时尝试创建单例对象,所以需要使用互斥锁来保证只有一个线程能够成功创建对象,避免出现多个实例的情况。
-
-
成员函数:
-
singleton()
:私有构造函数,输出 “唯构造函数”,防止外部直接实例化该类。将构造函数设为私有,是单例模式的关键实现方式之一,这样外部代码就无法通过new
操作直接创建该类的对象,只能通过类提供的静态方法来获取唯一的实例。 -
static singleton* constructer()
:静态函数,用于获取单例对象实例。首先调用m.lock()
加锁,然后检查only
是否为NULL
,若为NULL
,则模拟耗时操作(通过sleep(1)
)后创建单例对象,最后调用m.unlock()
解锁并返回单例对象实例。加锁操作是为了确保在检查和创建单例对象的过程中,不会有其他线程同时进行相同的操作,从而保证单例对象的唯一性。检查only
是否为NULL
是判断单例对象是否已经被创建,如果尚未创建,则进行创建操作。模拟耗时操作(这里使用sleep(1)
)是为了更真实地模拟在实际场景中可能出现的一些复杂初始化逻辑,在实际应用中,这个部分可能会涉及到数据库连接初始化、文件读取等耗时操作。创建完单例对象后,通过解锁操作释放互斥锁,允许其他线程继续尝试获取单例对象。
-
(三)thread_main 函数
-
功能:作为线程执行函数,用于在新线程中获取单例对象实例并打印其地址。在多线程编程中,每个线程都有自己的执行函数,
thread_main
函数就是为新创建的线程指定的执行函数,它负责在新线程的上下文中完成获取单例对象实例并进行相关操作(这里是打印地址)的任务。 -
实现:通过调用
singleton::constructer()
获取单例对象实例,将其存储在指针s
中,然后使用std::cout
打印该指针的值(即单例对象的地址),最后返回0
表示线程正常结束。当新线程启动后,会执行这个函数,首先调用singleton
类的constructer
静态方法获取单例对象实例,然后通过std::cout
将该实例的地址输出到控制台,这样可以直观地看到在不同线程中获取到的是否是同一个单例对象实例。最后返回0
是一种常见的线程执行函数返回值约定,表示线程正常执行完毕。
(四)main 函数
-
功能:程序的入口点,负责创建线程并在主线程中获取单例对象实例,展示多线程环境下单例模式的应用。
main
函数是 C++ 程序的起始执行点,在这个函数中,通过创建新线程并在主线程和新线程中都获取单例对象实例,来验证在多线程环境下单例模式的正确性和线程安全性。 -
实现步骤:
-
声明
pthread_t
类型的变量id
用于存储线程标识符。pthread_t
是 POSIX 线程库中定义的用于表示线程标识符的类型,通过这个变量来标识和管理创建的线程。 -
调用
pthread_create(&id, 0, thread_main, 0)
创建一个新线程,线程执行函数为thread_main
。pthread_create
函数用于创建一个新的线程,第一个参数是指向线程标识符变量的指针,用于返回新创建线程的标识符;第二个参数是一个指向线程属性对象的指针,这里传递0
表示使用默认属性;第三个参数是新线程要执行的函数指针,即thread_main
函数;第四个参数是传递给新线程执行函数的参数,这里传递0
表示不传递额外参数。 -
在主线程中调用
singleton::constructer()
获取单例对象实例并打印其地址。在主线程中,通过调用singleton
类的constructer
静态方法获取单例对象实例,并将其地址输出到控制台,用于和新线程中获取的单例对象实例地址进行对比。 -
调用
pthread_join(id, 0)
等待创建的线程结束。pthread_join
函数用于阻塞当前线程(这里是主线程),直到指定的线程(通过id
标识)执行完毕。这样可以确保主线程在新线程完成任务后再继续执行后续操作,避免出现主线程提前结束而新线程还未完成任务的情况。 -
再次调用
pthread_create(&id, 0, thread_main, 0)
创建新线程,重复上述获取单例对象实例并打印地址的操作,最后等待该线程结束,程序返回0
。通过再次创建新线程并重复获取单例对象实例的操作,进一步验证在多线程环境下单例模式的可靠性和线程安全性,确保在多次创建线程的情况下,都能正确获取到唯一的单例对象实例。
-
三、代码运行流程
-
程序启动,进入
main
函数。程序从main
函数开始执行,这是 C++ 程序的入口点。 -
创建第一个线程,该线程开始执行
thread_main
函数。在main
函数中,通过调用pthread_create
函数创建一个新线程,新线程启动后开始执行thread_main
函数。 -
在
thread_main
函数中,调用singleton::constructer
获取单例对象。此时如果单例对象尚未创建,constructer
函数会加锁,检查发现only
为NULL
,然后模拟耗时操作(睡眠 1 秒),创建单例对象,最后解锁并返回单例对象实例,线程打印单例对象地址。新线程在执行thread_main
函数时,首先调用singleton
类的constructer
静态方法获取单例对象。如果这是第一次创建单例对象,那么constructer
函数会通过加锁操作保证只有当前线程能够进行创建操作,检查到only
为NULL
后,模拟耗时操作(这里是睡眠 1 秒),然后创建单例对象,最后解锁并返回创建好的单例对象实例,新线程将该实例的地址打印出来。 -
在主线程中,也调用
singleton::constructer
获取单例对象,由于此时单例对象已被创建,所以直接返回已创建的对象实例并打印地址。在主线程中,同样调用singleton
类的constructer
静态方法获取单例对象,因为此时单例对象已经在新线程中被创建,所以constructer
函数直接返回已创建的单例对象实例,并将其地址打印出来。 -
主线程调用
pthread_join
等待第一个线程结束。主线程通过调用pthread_join
函数,阻塞自身直到第一个创建的新线程执行完毕,确保主线程和新线程之间的执行顺序和同步性。 -
再次创建第二个线程,该线程同样执行
thread_main
函数获取单例对象,由于单例对象已存在,直接返回并打印地址。在第一个新线程结束后,主线程再次创建一个新线程,这个新线程也执行thread_main
函数来获取单例对象。由于单例对象已经存在,所以constructer
函数直接返回已存在的单例对象实例,并将其地址打印出来。 -
主线程再次调用
pthread_join
等待第二个线程结束,程序结束。主线程再次通过调用pthread_join
函数,等待第二个新线程执行完毕,然后程序结束运行。 -
在
singleton
类中新增成员变量isDestroyed
:用于标记单例对象是否已经被销毁,初始化为false
。这个变量的作用是在多个线程同时尝试销毁单例对象或者在程序运行过程中多次判断单例对象是否已销毁时,提供一个准确的状态标识,避免重复销毁或者误判。 -
新增
destroy
静态函数:-
首先调用
m.lock()
加锁,确保在销毁单例对象的过程中,不会有其他线程同时进行相关操作。 -
然后检查
only
是否为NULL
并且isDestroyed
是否为false
,如果满足条件,说明单例对象存在且尚未被销毁,此时调用delete only
释放单例对象占用的内存,将only
指针设为NULL
,并将isDestroyed
设为true
。 -
最后调用
m.unlock()
解锁,允许其他线程继续执行。
-
-
在
main
函数中新增singleton::destroy()
调用:在主线程等待创建的线程结束后,调用singleton
类的destroy
静态函数来销毁单例对象,释放其占用的资源,避免内存泄漏问题。
四、主要事项
-
代码中使用了 POSIX 线程库,在编译时需要链接该库,例如在 Linux 环境下使用
g++
编译,需添加-pthread
选项(如g++ -o main main.cpp -pthread
) 。POSIX 线程库是一个提供多线程编程接口的库,为了让编译器能够正确链接和使用这个库中的函数和类型,需要在编译时添加-pthread
选项,否则会出现编译错误,提示找不到相关的函数和类型定义。 -
虽然代码实现了基本的线程安全的单例模式,但在实际应用中,还需考虑单例对象的销毁时机和内存管理等问题,目前代码中未涉及单例对象的销毁逻辑。在实际应用中,单例对象可能会占用一些系统资源,如内存、文件句柄等。当程序结束或不再需要单例对象时,需要正确地释放这些资源。目前的代码中没有实现单例对象的销毁逻辑,可能会导致内存泄漏等问题。可以考虑在程序退出时手动释放单例对象占用的资源,或者使用智能指针等技术来自动管理单例对象的生命周期。
-
代码中的
sleep(1)
仅为简单模拟耗时操作,实际场景中可能存在更复杂的业务逻辑,要确保加锁和解锁操作能正确保护相关资源。在实际应用中,单例对象的创建过程可能会涉及到数据库连接、文件读取、网络请求等复杂的操作,这些操作可能会比简单的睡眠操作耗时更长,并且可能会出现各种异常情况。因此,在编写实际的业务逻辑时,需要仔细考虑加锁和解锁的范围和时机,确保在整个操作过程中,互斥锁能够正确地保护相关资源,避免出现数据竞争和不一致问题。同时,还需要处理可能出现的异常情况,保证程序的健壮性。
五、代码实现展示
六、源代码
#include <iostream>
#include <pthread.h>
#include <unistd.h> // 包含 sleep 函数所需的头文件// 定义一个互斥锁类
class Mutex {
public:// 内部使用pthread_mutex_t来表示互斥锁pthread_mutex_t m;public:// 构造函数,初始化互斥锁Mutex() {pthread_mutex_init(&m, 0);}// 加锁函数void lock() {pthread_mutex_lock(&m);}// 解锁函数void unlock() {pthread_mutex_unlock(&m);}// 析构函数,销毁互斥锁~Mutex() {pthread_mutex_destroy(&m);}
};// 单例类
class singleton {
private:// 私有构造函数,防止外部直接实例化singleton() {std::cout << "唯一构造函数" << std::endl;}// 静态成员,用于存储唯一的单例对象实例static singleton* only;// 静态互斥锁对象,用于在多线程创建单例对象时进行同步static Mutex m;// 静态成员,用于标记单例对象是否已被销毁static bool isDestroyed;public:// 静态函数,用于获取单例对象实例static singleton* constructer() {m.lock();try {if (only == NULL &&!isDestroyed) {sleep(1);only = new singleton;}} catch (...) {m.unlock();throw;}m.unlock();return only;}// 静态函数,用于销毁单例对象static void destroy() {m.lock();if (only != NULL && !isDestroyed) {delete only;only = NULL;isDestroyed = true;}m.unlock();}~singleton() {std::cout << "单例对象析构函数" << std::endl;}
};// 初始化单例对象指针为NULL
singleton* singleton::only = NULL;
// 初始化静态互斥锁对象
Mutex singleton::m;
// 初始化单例对象销毁标记为false
bool singleton::isDestroyed = false;// 线程执行函数
void* thread_main(void* arg) {// 获取单例对象实例singleton* s = singleton::constructer();std::cout << s << std::endl;return 0;
}int main(int argc, const char** argv) {pthread_t id;// 创建线程pthread_create(&id, 0, thread_main, 0);// 获取单例对象实例(主线程也获取)singleton* s = singleton::constructer();std::cout << s << std::endl;// 等待线程结束pthread_join(id, 0);// 销毁单例对象singleton::destroy();return 0;
}
相关文章:
《C++多线程下单例 “锁钥” 法则》
一、概述 本文章介绍了一段 C 代码,该代码实现了在多线程环境下的单例模式。单例模式确保一个类只有一个实例,并提供全局访问点。在多线程场景中,需要额外的同步机制来保证单例对象创建的线程安全性。单例模式在许多场景中都有重要应用&#…...
WEB或移动端常用交互元素及组件 | Axure / 元件类型介绍(表单元件、菜单和表格 、流程元件、标记元件)
文章目录 引言I Axure / 元件类型介绍基本元件表单元件菜单和表格流程元件标记元件II Axure 基础Axure / 常用功能介绍Axure / 常用元素实例Axure / 动态交互实例Axure / 常用设计分辨率推荐III Axure / 创建自己的元件库元件库作用元件库的创建及使用引言 I Axure / 元件类型介…...
开发环境解决Secure Cookie导致302重定向
问题现象与根源分析 故障现象 前端本地开发时(HTTP协议),调用接口返回302 Found状态码浏览器控制台警告:“Cookie被阻止,因为设置了Secure属性但未通过HTTPS传输”登录态无法保持,页面陷入重定向循环 技…...
华为三进制逻辑与高维量子计算的对比分析
此博客深入探讨华为三进制逻辑状态的技术意义,并与高维量子计算系统进行对比。文章将全面展开技术原理、实现机制、计算能力对比、未来应用前景等方面的内容。 目录 引言 华为三进制逻辑的创新意义 2.1 二进制逻辑的局限与历史探索 2.2 三进制逻辑的优势ÿ…...
网红指路机器人是否支持环境监测功能?
嘿呀,你可知道?如今的叁仟网红指路机器人那可太牛啦!它们可不单单局限于为行人指明方向,还纷纷兼职当起了 “环境小卫士”,为咱们的城市生活注入了前所未有的超智能便利。就拿那个依托叁仟智慧杆打造的数智指路机器人来…...
【进阶】vscode 中使用 cmake 编译调试 C++ 工程
基于 MSYS2 的 MinGW-w64 GCC 工具链与 CMake 构建系统,结合VSCode及其扩展插件( ms-vscode.cmake-tools),可实现高效的全流程C开发调试。既可通过 VSCode 可视化界面(命令面板、状态栏按钮)便捷完成配置、…...
突发,国行 iPhone 17,支持 eSIM
古人云“无心生大用”,往往你感到绝望的时候,转机就莫名其妙的来了。 根据供应链的最新消息,国行 iPhone 17 Air,有望用上 eSIM。 不仅如此,国产手机厂商,也计划推出类似iPhone 17 Air的超薄机型…...
红宝书第二十二讲:详解JavaScript类型化数组与二进制数据处理
红宝书第二十二讲:详解JavaScript类型化数组与二进制数据处理 资料取自《JavaScript高级程序设计(第5版)》。 查看总目录:红宝书学习大纲 一、为什么需要类型化数组? 普通JavaScript数组(Array࿰…...
Elasticsearch安全与权限控制指南
在Elasticsearch维护中,安全管理是保障数据合规性和集群稳定性的关键。本文将详细介绍用户与角色管理、索引/字段级权限控制、HTTPS加密通信、审计日志与合规性检查等核心安全实践,希望可以帮助你构建更安全的Elasticsearch环境。 1 用户与角色管理 1.1…...
SAP 学习笔记 - 系统移行业务 - MALSY(由Excel 移行到SAP 的收费工具)
以前有关移行,也写过一些文章,比如 SAP 学习笔记 - 系统移行业务 - Migration cockpit工具 - 移行Material(品目)-CSDN博客 SAP 学习笔记 - 系统移行业务 - Migration cockpit工具2 - Lot导入_sap cockpit-CSDN博客 SAP学习笔记…...
【群智能算法改进】一种改进的蜣螂优化算法IDBO[3](立方混沌映射Cubic、融合鱼鹰勘探策略、混合高斯柯西变异)【Matlab代码#92】
文章目录 【获取资源请见文章第5节:资源获取】1. 原始DBO算法2. 改进后的IDBO算法2.1 立方混沌映射Cubic种群初始化2.2 融合鱼鹰勘探策略2.3 混合高斯柯西变异 3. 部分代码展示4. 仿真结果展示5. 资源获取 【获取资源请见文章第5节:资源获取】 1. 原始DB…...
《异常检测——从经典算法到深度学习》30. 在线服务系统中重复故障的可操作和可解释的故障定位
《异常检测——从经典算法到深度学习》 0 概论1 基于隔离森林的异常检测算法 2 基于LOF的异常检测算法3 基于One-Class SVM的异常检测算法4 基于高斯概率密度异常检测算法5 Opprentice——异常检测经典算法最终篇6 基于重构概率的 VAE 异常检测7 基于条件VAE异常检测8 Donut: …...
座舱与智驾“双轮驱动”,芯擎科技打造智能汽车“芯”标杆
在比亚迪、吉利、奇瑞等各大主机厂打响“全民智驾”的关键时期,以芯擎科技为代表中国芯片厂商开始“放大招”。 2025年3月27日,芯擎科技在南京举办了“擎随芯动、智融万象”生态科技日,重磅发布了“星辰一号”、“星辰一号Lite”,…...
观察者模式在Java单体服务中的运用
观察者模式主要用于当一个对象发生改变时,其关联的所有对象都会收到通知,属于事件驱动类型的设计模式,可以对事件进行监听和响应。下面简单介绍下它的使用: 1 定义事件 import org.springframework.context.ApplicationEvent;pu…...
html5时钟升级!支持切换深浅模式 Canvas实现现代化动态时钟
HTML5 Canvas实现现代化动态时钟 这里写目录标题 HTML5 Canvas实现现代化动态时钟项目介绍技术实现1. 项目架构2. Canvas绘图实现2.1 表盘绘制2.2 刻度绘制2.3 指针绘制 3. 动画效果4. 主题切换 项目亮点技术要点总结项目收获改进方向结语 项目介绍 本项目使用HTML5 Canvas技术…...
Scala(2)
For循环控制 循环守卫 基本语法 for(i <- 1 to 3 if i ! 2) { print(i " ") }println() 说明: 循环守卫,即循环保护式(也称条件判断式,守卫)。保护式为 true 则进入循环体内部,为false 则跳…...
DataGear 5.3.0 制作支持导出表格数据的数据可视化看板
DataGear 内置表格图表底层采用的是DataTable表格组件,默认并未引入导出数据的JS支持库,如果有导出表格数据需求,则可以在看板中引入导出相关JS支持库,制作具有导出CSV、Excel、PDF功能的表格数据看板。 在新发布的5.3.0版本中&a…...
项目-苍穹外卖(十六) Apache ECharts+数据统计
一、介绍 二、营业额统计 需求分析和设计: Controller: Service: /*** 营业额统计* param begindate* param enddate* return* */Overridepublic TurnoverReportVO turnoverStatistics(LocalDate begindate, LocalDate enddate) {//创建时间集合List<LocalDate&…...
使用 PowerShell 脚本 + FFmpeg 在 Windows 系统中批量计算 MP4视频 文件的总时长
步骤 1:安装 FFmpeg 访问 FFmpeg 官网(Download FFmpeg),下载 Windows 版编译包(如 ffmpeg-release-full.7z)。或者到(https://download.csdn.net/download/zjx2388/90539014)下载完整资料 解压文件&#…...
低成本文件共享解决方案:Go File本地Docker部署与外网访问全记录
文章目录 前言1. 安装Docker2. Go File使用演示3. 安装cpolar内网穿透4. 配置Go File公网地址5. 配置Go File固定公网地址 前言 在这个信息爆炸的时代,谁还没遇到过这样的囧事呢?正在办公室电脑上赶工报告,手机却突然蹦出一条紧急邮件&#…...
python文件的基本操作和文件读写
目录 文件的基本操作 文件读写 文件的基本操作 Python 中对文件的基本操作主要包括打开文件、读取文件、写入文件和关闭文件等操作。下面是一个简单的示例: 打开文件: file open(example.txt, r) # 使用 open() 函数打开一个名为 example.txt 的文…...
大数据与datax1.0
一、datax含义 是一个数据搬运工具 二、需要注意的点 插件(plugin)下面的reader和writer 要删除(第一步执行肯定会报错 所以请记得一定要删除reader和writer下的隐藏文件) 三、心得 做任何事要事半功倍,而不要事倍功半,好的学习方法永远比盲目的努力更重要--------谨记3.31…...
蚂蚁集团主导的ISO密码学国际标准立项,纳入国产算法
蚂蚁集团主导的ISO密码学国际标准 ISO 25330-3 立项, 国产算法Ferret成为标准方案。 近日,在美国弗吉尼亚州举行的 ISO/IEC JTC 1/SC 27 全体会议上,ISO/IEC 25330第三部分《Information Security — Oblivious Transfer — Part 3: Obliv…...
【新人系列】Golang 入门(十):错误处理详解 - 上
✍ 个人博客:https://blog.csdn.net/Newin2020?typeblog 📝 专栏地址:https://blog.csdn.net/newin2020/category_12898955.html 📣 专栏定位:为 0 基础刚入门 Golang 的小伙伴提供详细的讲解,也欢迎大佬们…...
Unity 2022.3.x部分Android设备播放视频黑屏问题
Android平台视频兼容性问题很多…类似的黑屏问题真的很头大,总结一些常见问题: 1. 视频文件不支持压缩 如果使用AssetBundle加载视频,这个AssetBundle压缩格式要选None。有人可能会说最新版Unity已经支持bundle压缩下播放视频,稳…...
基于Python的Django框架的个人博客管理系统
标题:基于Python的Django框架的个人博客管理系统 内容:1.摘要 本文围绕基于Python的Django框架构建个人博客管理系统展开。背景方面,随着互联网发展,个人博客成为信息分享与交流重要平台,传统博客管理系统在功能与灵活性上存在不足。目的是开…...
Unity加载OSGB倾斜摄影数据
Unity加载OSGB倾斜摄影数据 显而易见有一个最方便的办法就是使用CesiumForUnity确定是可以通过osgb数据转换成3dtiles进行加载的,然而有没有直接加载osgb格式数据的方法呢? 我们知道osgb的osg推出的倾斜摄影数据的数据结构,所以,…...
RabbitMQ简单介绍和安装
RabbitMQ简单介绍 一.RabbitMQ介绍二.RabbitMQ的作用1.异步解耦2.流量削峰3.消息分发4.延迟通知 三.RabbitMQ安装(Ubuntu)1.先安装Erlang2.安装RabbitMQ3.安装RabbitMQ的管理界面4.创建虚拟机5.端口号信息 四.工作原理图 一.RabbitMQ介绍 RabbitMQ 是一款…...
【清华大学】DeepSeek政务应用场景与解决方案
目录 一、政务数字化转型三阶段演进二、人工智能政务应用场景四大方向 三、技术方案核心技术 四、解决方案案例1. 公文写作2. 合同协议智能审查3. 行政执法4. 就业指导 五、风险及对策六、落地大四步法七、未来发展展望AI职业替代逻辑空间智能与具身智能人机共生 一、政务数字化…...
spring boot自动装配原理
springboot自动装配几乎是现在面试必问的面试题,要是逐行分析自动装配流程肯定是很复杂的,因此我们从大体上来梳理即可。 一、 自动装配总览 首先要搞清楚两个问题,springboot自动装配是什么?解决了什么问题? springbo…...
【SDMs分析1】基于ENMTools R包的生态位分化分析和图像绘制(identity.test())
基于ENMTools包的生态位分化 1. 写在前面2. 生态位分化检验案例13. 生态位分化检验案例21. 写在前面 最近学了一个新的内容,主要是关于两个物种之间生态位分化检验的 R 语言代码。生态位分化是物种分布模型(SDM )研究中的关键部分,许多 SCI 论文都会涉及这一分析。该方法主…...
蓝桥杯比赛python程序设计——纯职业小组
问题描述 在蓝桥王国,国王统治着一支由 nn 个小队组成的强大军队。每个小队都由相同职业的士兵组成。具体地,第 ii 个小队包含了 bibi 名职业为 aiai 的士兵。 近日,国王计划在王宫广场举行一场盛大的士兵检阅仪式,以庆祝王…...
【Git教程】将dev分支合并到master后,那么dev分支该如何处理
将 dev 合并到 master 后的分支状态与操作指南 1. 合并后的分支状态 dev 分支不会消失: Git 的 git merge 命令仅将 dev 的内容合并到 master,不会删除 dev 分支。合并后,dev 分支仍然存在,其历史记录和代码保持不变。 分支的 H…...
python系统之综合案例:用python打造智能诗词生成助手
不为失败找理由,只为成功找方法。所有的不甘,因为还心存梦想,所以在你放弃之前,好好拼一把,只怕心老,不怕路长。 python系列之综合案例 前言一、项目描述二、项目需求三、 项目实现1、开发准备2、代码实现 …...
HCIA-数据通信datacom认证
文章目录 一、数据通信简介1.1 标准协议1.2 数据传输过程 二、通用路由平台VRP2.1 VRP简介2.2 命令行基础 三 、网络层协议IP3.1 数据封装3.2 数据包传输2.3 IP地址2.4 子网划分2.5 ICMP 四、IP路由基础4.1 路由概述4.2 路由表4.3 路由转发4.4 静态路由4.5 动态路由4.6 路由高级…...
学以致用,基于OpenCV的公摊面积估算程序
由于很多户型图并没有标注各个房间或者走廊的面积,亦或比较模糊,且很多人并不具备迅速口算多个小数相加再做除法的能力,本帖通过程序粗略计算公摊比例。由于非专业人士,公摊面积涉及到很多建筑学的专业公式,因此本帖只…...
Odoo/OpenERP 和 psql 命令行的快速参考总结
Odoo/OpenERP 和 psql 命令行的快速参考总结 psql 命令行选项 选项意义-a从脚本中响应所有输入-A取消表数据输出的对齐模式-c <查询>仅运行一个简单的查询,然后退出-d <数据库名>指定连接的数据库名(默认为当前登录用户名)-e回显…...
Ubuntu20.04安装OpenVINO环境以及YOLOv8 C++部署测试
深度学习 文章目录 深度学习一、三种推理框架介绍1、OpenVINO介绍2、TensorRT介绍3、Mediapipe介绍 二、三种框架的对比1、框架自身比较2.1、从模型部署上:2.2.从支持深度学习模型上:2.3.从应用平台上:2.4.从上手的难易程度上: 2、应用平台比…...
uniapp微信小程序封装navbar组件
一、 最终效果 二、实现了功能 1、nav左侧返回icon支持自定义点击返回事件(默认返回上一步) 2、nav左侧支持既显示返回又显示返回首页icon 3、nav左侧只显示返回icon 4、nav左侧只显示返回首页icon 5、nav左侧自定义left插槽 6、nav中间支持title命名 7…...
Docker中安装MySQL--------【详细图解】
1.根据所需拉取镜像---------不指定版本会下载最新版 docker pull mysql:8.0.27 2.查看所拉取的镜像 docker images 3.在/usr/local下创建docker、mysql目录 cd /usr/local mkdir docker mkdir mysql 4.进入mysql文件夹 cd mysql 5.创建config文件夹 mkdir config 6.编写配…...
QT基础:安装与简介
QT初级 1、简介1.1 安装1.2 设置1.3 在VS中配置Qt1.3 帮助文档 2、Qt项目2.1 创建项目2.1 项目文件2.2 Qt中的窗口类窗口显示 2.3 坐标体系2.4 内存回收 1、简介 QT是一个跨平台的C应用程序开发框架。几乎支持所有的平台, 可用于桌面程序开发以及嵌入式开发。 Qt是标准 C 的扩…...
智能打印预约系统:微信小程序+SSM框架实战项目
微信小程序打印室预约系统,采用SSM(SpringSpringMVCMyBatis)经典框架组合。 一、系统核心功能详解 1. 智能化管理后台 用户数据看板打印店资源管理预约动态监控服务评价系统 2. 微信小程序端 智能定位服务预约时段选择文件…...
AWTK-WEB 快速入门(6) - JS WebSocket 应用程序
WebSocket 可以实现双向通信,适合实时通信场景。本文介绍一下使用 Javacript 语言开发 AWTK-WEB 应用程序,并用 WebSocket 与服务器通讯。 用 AWTK Designer 新建一个应用程序 先安装 AWTK Designer: https://awtk.zlg.cn/web/index.html …...
一.搭建ubuntu系统服务器
搭建ubuntu系统服务器 一:Ubantu下载及安装1.Ubuntu的U盘系统安装工具制作2.Ubuntu系统安装 二.安装ssh实现远程连接1.安装OpenSSH服务器2.启动SSH服务并设置开机自启3.配置文件4.配置防火墙5.处理SELinux(仅限CentOS/RHEL)6.设置和修改SSH密…...
[python]基于yolov8实现热力图可视化支持图像视频和摄像头检测
YOLOv8 Grad-CAM 可视化工具 本工具基于YOLOv8模型,结合Grad-CAM技术实现目标检测的可视化分析,支持图像、视频和实时摄像头处理。 功能特性 支持多种Grad-CAM方法实时摄像头处理视频文件处理图像文件处理调用简单 环境要求 Python 3.8需要电脑带有…...
微软 GraphRAG 项目学习总结
微软2024年4月份发布了一篇《From Local to Global: A GraphRAG Approach to Query-Focused Summarization》(GraphRAG:从局部到全局的查询式摘要方法)论文,提出了一种名为GraphRAG的检索增强生成(RAG)方法…...
DeepSeek结合MCP Server与Cursor,实现服务器资源的自动化管理
MCP Server是最近AI圈子中又一个新的热门话题。很多用户都通过结合大语言模型、MCP Server,实现了一些工具流的自动化,例如,你只需要给出文字指令,就可以让Blender自动化完成建模的工作。你有没有想过,利用MCP来让AI A…...
DFX架构详解:构建面向全生命周期的卓越设计体系
引言 在当今高度竞争的市场环境中,产品开发已不再是单纯的功能实现,而是需要从设计源头考虑制造效率、用户需求、成本控制、环境兼容性等多维目标。DFX(Design for X)架构作为一种系统化的设计方法论,正成为企业实现产…...
如何在 Vue 项目中使用 Vite 和 Cordova 动态加载 Layui 和 DTree
随着前端开发工具的不断进步,Vue 项目的构建工具也从 Webpack 升级到了 Vite。Vite 的快速构建和热更新功能使得开发体验大大提升。 本文将介绍如何在迁移至 Vite 后,动态加载 Layui 和 DTree 库,并兼容 Cordova 应用中的资源路径。 1. Vite …...
如何在 vue 渲染百万行数据,vxe-table 渲染百万行数据性能对比,超大量百万级表格渲染
vxe-table 渲染百万行数据性能对比,超大量百万级表格渲染;如何在 vue 渲染百万行数据;当在开发项目时,遇到需要流畅支持百万级数据的表格时, vxe-table 就可以非常合适了,不仅支持强大的功能,虚…...