C++11 thread
文章目录
- C++11 线程库
- 线程对象的构造方式
- 无参的构造函数
- 调用带参的构造函数
- 调用移动构造函数
- thread常用成员函数
- this_thread命名空间
- join && detach
- mutex
C++11 线程库
线程对象的构造方式
无参的构造函数
1、调用无参的构造函数,调用无参的构造函数创建出来的线程对象没有关联任何线程函数,即没有启动任何线程
thread t1;
2、thread提供了移动赋值函数,当后续需要让该线程对象与线程函数关联时,可以以带参的方式创建一个匿名对象,然后调用移动赋值将该匿名对象关联线程的状态转移给该线程对象
void Print(size_t n , const std::string& s)
{for (size_t i = 0; i < n; i++){std::cout << std::this_thread::get_id() << ":" << i << std::endl;}
}
int main()
{int n = 10;// 创建n个线程执行Printstd::vector<std::thread> vthd(n);size_t j = 0;for (auto& thd : vthd){// 移动赋值thd = std::thread(Print, 10, "线程" + std::to_string(j++));}for (auto& thd : vthd){thd.join();}return 0;}
场景:
实现线程池的时候, 需要先创建一批线程,但,一开始这些线程什么也不做,当有任务到来时再让这些线程来处理这些任务。
#include <iostream>
#include <vector>
#include <thread>
#include <functional>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <atomic>class ThreadPool {
public:ThreadPool(size_t threads = 4); // 构造函数,可以指定线程池的大小~ThreadPool(); // 析构解函数void enqueue(std::function<void()> task); // 添加任务到线程池private:std::vector<std::thread> workers; // 线程向量std::queue<std::function<void()>> tasks; // 任务队列队std::mutex queue<std::function<void()>> completedTasks;std::condition_variable cond; // 条件变量bool stop; // 停止标志void work(); // 线程工作函数
};// 构造函数初始化线程池
ThreadPool::ThreadPool(size_t threads) : stop(false) {for(size_t i = 0; i < threads; ++i)workers.emplace_back(std::thread(&ThreadPool::work, this));
}// 析构解函数等待所有线程完成
ThreadPool::~ThreadPool() {{std::unique_lock<std::mutex> lock(this->mtx);this->stop = true;}cond.notify_all();for(std::thread &worker : workers) {if(worker.joinable()) {worker.join(); // 等待线程结束}}
}// 添加任务到线程池
void ThreadPool::enqueue(std::function<void()> task) {{std::unique_lock<std::mutex> lock(mtx);if(stop)throw std::runtime_error("enqueue on stopped ThreadPool");tasks.emplace(task);}cond.notify_one();
}void ThreadPool::work() {while(true) {std::function<void()> task;{std::unique_lock<std::mutex> lock(this->mtx);while(tasks.empty()) {cond.wait(lock); // 如果没有任务,等待}task = std::move(tasks.front());tasks.pop();}();task(); // 执行任务}
}
在这个示例中,ThreadPool
类管理一组工作线程。构造函数创建指定数量的线程,每个线程都调用work
方法等待并执行任务。enqueue
方法用于添加新任务到队列,如果线程池已经停止,则抛出异常。每个工作线程在接收到任务后会出队列并执行它
调用带参的构造函数
template <class Fn, class... Args>
explicit thread (Fn&& fn, Args&&... args);
fn
:可调用对象,比如函数指针、仿函数、lambda表达式、被包装器包装后的可调用对象等。args...
:调用可调用对象fn时所需要的若干参数
调用移动构造函数
用一个右值线程对象来构造一个线程对象
void func(int n)
{for (int i = 0; i <= n; i++){cout << i << endl;}
}
int main()
{thread t3 = thread(func, 10);t3.join();return 0;
}
线程是操作系统中的一个概念,线程对象可以关联一个线程,用来控制线程以及获取线程的状态。
如果创建线程对象时没有提供线程函数,那么该线程对象实际没有对应任何线程。
如果创建线程对象时提供了线程函数,那么就会启动一个线程来执行这个线程函数,该线程与主线程一起运行。
thread类是防拷贝的,不允许拷贝构造和拷贝赋值,但是可以移动构造和移动赋值,可以将一个线程对象关联线程的状态转移给其他线程对象,并且转移期间不影响线程的执行
thread常用成员函数
join ,对该线程进行等待,在等待的线程返回之前,调用join函数的线程将会被阻塞
joinable , 判断该线程是否已经执行完毕,如果是则返回true,否则返回false
detach ,将该线程与创建线程进行分离,被分离后的线程不再需要创建线程调用join函数对其进行等待
get_id , 获取该线程的id
swap , 将两个线程对象关联线程的状态进行交换
joinable函数还可以用于判定线程是否是有效的,
如果是以下任意情况,则线程无效:
采用无参构造函数构造的线程对象。(该线程对象没有关联任何线程)
线程对象的状态已经转移给其他线程对象。(已经将线程交给其他线程对象管理)
线程已经调用join或detach结束。(线程已经结束)
thread的成员函数get_id
可以获取线程的id,但该方法必须通过线程对象来调用get_id
函数
如果要在线程对象关联的线程函数中获取线程id,调用this_thread
命名空间下的get_id
函数
void func()
{cout << this_thread::get_id() << endl; //获取线程id
}
int main()
{thread t(func);t.join();return 0;
}
this_thread命名空间
yield | 当前线程“放弃”执行,让操作系统调度另一线程继续执行 |
---|---|
sleep_until | 让当前线程休眠到一个具体时间点 |
sleep_for | 让当前线程休眠一个时间段 |
线程传参
1、使用lambda
#include<thread>
#include<iostream>
#include<vector>
#include<string>int main()
{size_t n1 = 5;size_t n2 = 5;/*std::cin >> n1 >> n2;*/std::thread t1( [n1](){for (size_t i = 0; i < n1; i++){//拿到该线程的线程idstd::cout << std::this_thread::get_id() << ":" << i << " " << std::endl;}} );std::thread t2([n2](){for (size_t i = 0; i < n2; i++){//拿到该线程的线程idstd::cout << std::this_thread::get_id() << ":" << i << " " << std::endl;}} );t2.join();t1.join();return 0;
}
join && detach
启动一个线程后,当这个线程退出时,需要对该线程所使用的资源进行回收,否则可能会导致内存泄露等问题。thread库提供了两种回收线程资源的方式:
1、join
主线程创建新线程后,调用join函数等待新线程终止,当新线程终止时join
函数就会自动清理线程相关的资源
join
函数清理线程的相关资源后,thread对象与已销毁的线程就没有关系了,因此一个线程对象一般只会使用一次join
,如果一个线程对象使用多次join , 程序会崩溃
void func(int n)
{for (int i = 0; i <= n; i++){cout << i << endl;}
}
int main()
{thread t(func, 20);t.join();t.join(); //程序崩溃return 0;
}
2、detach
主线程创建新线程后,也可以调用detach函数将新线程与主线程进行分离,分离后新线程会在后台运行,其所有权和控制权将会交给C++运行库,此时C++运行库会保证当线程退出时,其相关资源能够被正确回收。
使用detach的方式回收线程的资源,一般在线程对象创建好之后就立即调用detach函数。
否则线程对象可能会因为某些原因,在后续调用detach函数分离线程之前被销毁掉,这时就会导致程序崩溃。
因为当线程对象被销毁时会调用thread的析构函数,而在thread的析构函数中会通过joinable判断这个线程是否需要被join,如果需要那么就会调用terminate终止当前程序(程序崩溃)
#include <iostream>
#include <thread>
#include <vector>void worker() {std::cout << "Working..." << std::endl;// 模拟耗时操作std::this_thread::sleep_for(std::chrono::seconds(2));std::cout << "Finished" << std::endl;
}int main() {std::vector<std::thread> threads;// 创建并分离多个线程for (int i = 0; i < 5; ++i) {threads.emplace_back(std::thread(worker));threads.back().detach(); // 分离线程}std::cout << "Main thread continues to run..." << std::endl;// 主线程可以继续执行其他任务,而不需要等待分离的线程// 等待所有线程完成(可选)for (auto& th : threads) {if (th.joinable()) {th.join();}}std::cout << "All threads finished" << std::endl;return 0;
}
过度使用分离线程可能会导致资源泄露,因为分离的线程将继续运行,即使主线程已经结束。因此,通常建议在可能的情况下使用join
来管理线程的生命周期。
mutex
C++11中,mutex中总共包了四种互斥量
1、std::mute
mutex锁是C++11提供的最基本的互斥量,mutex对象之间不能进行拷贝,也不能进行移动
mutex常用的成员函数:
lock | 对互斥量进行加锁 |
---|---|
try_lock | 尝试对互斥量进行加锁 |
unlock | 对互斥量进行解锁,释放互斥量的所有权 |
线程函数调用lock时,可能会发生以下三种情况:
1、如果该互斥量当前没有被其他线程锁住,则调用线程将该互斥量锁住,直到调用unlock之前,该线程一致拥有该锁。
#include <iostream>
#include <thread>
#include <mutex>std::mutex mtx; // 全局互斥锁void printBlock(int n) {mtx.lock(); // 获取锁,如果锁已经被其他线程占用,则等待for (int i = 0; i < n; ++i) {std::cout << "Thread " << std::this_thread::get_id() << " says " << i << std::endl;}mtx.unlock(); // 释放锁,其他线程可以获取该锁
}int main() {std::thread t1(printBlock, 1);std::thread t2(printBlock, 2);t1.join();t2.join();return 0;
}
mtx
是一个全局互斥锁,所以一次只能有一个线程执行printBlock
函数。这意味着即使两个线程几乎同时运行,输出也将是交错的,而不是同时打印,因为一个线程在打印时会锁定互斥锁,另一个线程必须等待
2、如果该互斥量已经被其他线程锁住,则当前的调用线程会被阻塞。
互斥锁(mutex)在多线程环境中的基本行为。互斥锁是一种同步机制,用于防止多个线程同时访问共享资源,从而避免数据竞争条件和不一致的状态。当一个线程尝试获取已经被其他线程持有的互斥锁时,该线程将被阻塞,直到互斥锁被释放
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>std::mutex mtx; // 全局互斥锁void worker(int id) {// 尝试获取锁mtx.lock();std::cout << "Thread " << id << " acquired the lock" << std::endl;// 模拟耗时的工作std::this_thread::sleep_for(std::chrono::milliseconds(500));std::cout << "Thread " << id << " released the lock" << std::endl;// 释放锁mtx.unlock();
}int main() {std::thread t1(worker, 1);std::thread t2(worker, 2);// 主线程稍作等待,以便 t1 有机会获取锁std::this_thread::sleep_for(std::chrono::milliseconds(100));// 尝试在 t1 持有锁时获取锁mtx.lock();std::cout << "Main thread acquired the lock" << std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟主线程持有锁mtx.unlock();t1.join();t2.join();return 0;
}
3、如果该互斥量被当前调用线程锁住,则会产生死锁(deadlock)。
如何使用局部变量加锁?
例1:用lambda
int main()
{size_t n1 = 10000;size_t n2 = 10000;/*std::cin >> n1 >> n2;*/int x = 0;std::mutex mtx;std::thread t1([&n1, &x ,&mtx]() {for (size_t i = 0; i < n1; i++){mtx.lock();x++;//拿到该线程的线程id//std::cout << std::this_thread::get_id() << ":" << i << " " << std::endl;mtx.unlock();}});std::thread t2([&n2, &x,&mtx]() {for (size_t i = 0; i < n2; i++){mtx.lock();//拿到该线程的线程idx++;//std::cout << std::this_thread::get_id() << ":" << i << " " << std::endl;mtx.unlock();}});t2.join();t1.join();std::cout << x;return 0;
}
例2:
void Print1(size_t n,size_t j , const std::string& s ,std::mutex & mtx) //锁必须传引用 ,锁不支持拷贝
{for (size_t i = 0; i < j+n; i++){mtx.lock();std::cout << std::this_thread::get_id() << ":" << i << std::endl;mtx.unlock();}
}
int main()
{int n = 10;// 创建n个线程执行Printstd::vector<std::thread> vthd(n);std::mutex mtx;std::thread t1(Print1, 100, 1, "hello", ref(mtx )); //必须加ref函数 ,否则锁不能以传引用的方式传参传过去std::thread t2(Print1, 100, 100000, "world", ref(mtx));t1.join();t2.join();return 0;}
例3
void Print1(size_t n, const std::string& s, std::mutex& mtx ,int & rx) //锁必须传引用 ,锁不支持拷贝
{for (size_t i = 0; i < n; i++){mtx.lock();std::cout << std::this_thread::get_id() << ":" << i << std::endl;++rx;mtx.unlock();std::this_thread::sleep_for(std::chrono::microseconds(1000));}
}int main()
{std::mutex mtx;int x = 10;std::thread t1(Print1, 5, "hello", std::ref(mtx), std::ref(x));std::thread t2(Print1,5, "world", std::ref(mtx), std::ref(x));std::cout << "线程1: " << t1.get_id() << std::endl;std::cout << "线程2: " << t2.get_id() << std::endl;t1.join();t2.join();std::cout << x << std::endl;return 0;
}
线程调用try_lock时,类似也可能会发生以下三种情况:
1、如果该互斥量当前没有被其他线程锁住,则调用线程将该互斥量锁住,直到调用unlock之前,该线程一致拥有该锁。
2、如果该互斥量已经被其他线程锁住,则try_lock调用返回false,当前的调用线程不会被阻塞。
3、如果该互斥量被当前调用线程锁住,则会产生死锁(deadlock)
相关文章:
C++11 thread
文章目录 C11 线程库线程对象的构造方式无参的构造函数调用带参的构造函数调用移动构造函数thread常用成员函数 this_thread命名空间join && detachmutex C11 线程库 线程对象的构造方式 无参的构造函数 1、调用无参的构造函数,调用无参的构造函数创建出来的线程对象…...
重生之我在异世界学编程之C语言:深入预处理篇(上)
大家好,这里是小编的博客频道 小编的博客:就爱学编程 很高兴在CSDN这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!! 本文目录 引言正文一、预处理的作用与流程…...
Java并发编程5--Java内存模型的基础
1.并发编程模型的两个关键问题 在并发编程中,需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体)。 通信是指线程之间以何种机制来交换信息。 在命令式编程中,线程之间的通…...
国密算法SM1、SM2、SM3和SM4 具体的使用和区别
国密算法是中国自主研发的密码算法,包括SM1、SM2、SM3和SM4,分别用于不同场景。以下是它们的具体使用和区别: SM1 对称加密算法 类型: 对称加密 密钥长度: 128位 使用场景: 用于数据加密和解密,适用于金融、政务等领域。 特点: …...
package.json的全面详解
在 Node.js 的世界里,package.json 文件占据着举足轻重的地位。它就像项目的“大脑”,掌控着项目的各种信息和依赖管理。下面,我们就深入剖析 package.json 文件,让你全面了解它的奥秘。 一、创建 package.json 在正式开始使用 …...
Linux、Docker与Redis核心知识点与常用命令速查手册
Linux、Docker与Redis核心知识点与常用命令速查手册 一、Linux基础核心 1. 核心概念 文件系统:采用树形结构,根目录为/权限机制:rwx(读/写/执行)权限,用户分为owner/group/others软件包管理: …...
通过TDE工业通讯网关解决设备通讯问题
设备通讯现状 在现代工业环境中,设备的通讯已成为提高生产效率和实现智能化管理的关键。随着工业4.0时代的到来,越来越多的智能设备被投入到生产运营中,这些设备通过集成特定的通信模块,形成了各自独立的自组网子系统。然而&…...
CI/CD(二)docker-compose安装Jenkins
1、docker-compose.yml version: 3.8services:jenkins:image: jenkins/jenkins:lts # 使用官方的 Jenkins LTS 镜像container_name: jenkinsuser: root # 如果需要以 root 用户运行ports:- "8080:8080" # Jenkins Web 界面端口- "50000:50000" # 用于 Jen…...
Linux操作系统3-文件与IO操作5(动态库与静态库的建立与加载)
上篇文章:Linux操作系统3-文件与IO操作4(软硬链接的建立与使用, 文件的三种时间)-CSDN博客 本篇代码Gitee仓库:myLerningCode/l21 橘子真甜/Linux操作系统与网络编程学习 - 码云 - 开源中国 (gitee.com) 本篇重点:动态库与静态库 目录 一. 静…...
同步异步日志系统-日志器的实现
该模块是针对于前几个模块的整合,也是直接面向客户所使用的,对于该模块的实现,我们基于:继承建造者设计模式来实现; 因此我们需要抽象出一个日志器抽象基类; 该基类提供的接口如下: 1、 debug();//站在用户的角度来说就是我只需要…...
webpack 项目优化(一)
一、构建速度优化 缩小文件处理范围 module: {rules: [{test: /\.js$/,exclude: /node_modules/, // 排除第三方库include: path.resolve(__dirname, src), // 限定处理范围use: babel-loader}] }利用缓存 Webpack 5 内置持久化缓存(直接配置)࿱…...
【撰写技巧】基金项目撰写跟踪交流会
基金申请书撰写完成后,提交前的审查是一个非常关键的步骤,这决定了你提交的材料是否符合要求,是否具备足够的说服力,以及是否能够通过专家评审。审查主要可以分为自我审查和团队审查两个层面。以下是基金申请书审查的主要内容和注…...
vue学习笔记
结合目录,点击阅读 文章目录 案例1:第一行vue代码App.vue引入Person.vue案例:改变变量的值案例:改变对象属性值案例:toRefs进行解包案例:给名字首字母大写案例:监视变量值的变化案例࿱…...
前端构建工具——Webpack和Vite的主要区别
目录 1. 设计理念2. 性能表现3. 使用场景4. 配置复杂度5. 生态系统6. 性能对比总结7. 选择建议 1. 设计理念 Webpack 设计理念:Webpack是一个通用的模块打包工具,它将项目中的各种资源(如JavaScript、CSS、图片等)视为模块&…...
Letsencrypt+certbot为域名免费配置ssl
1、基础概念 Let’s Encrypt 是一个提供免费 SSL/TLS 证书的认证机构,它的目标是让互联网上的通信更加安全,特别是普及 HTTPS。通过 Let’s Encrypt 提供的证书,网站可以使用加密连接,保护用户的数据传输。 Certbot 是一个由电子…...
达梦数据库针对慢SQL,收集统计信息清除执行计划缓存
前言:若遇到以下场景,大概率是SQL走错了执行计划: 1、一条SQL在页面上查询特别慢,但拿到数据库终端执行特别快 2、一条SQL在某种检索条件下查询特别慢,但拿到数据库终端执行特别快 此时,可以尝试按照下述步…...
IDEA通过Contince接入Deepseek
Deepseek 的出色表现,上期【Deepseek得两种访问方式与本地部署】 安装Continue插件 第一步、下载插件 在编辑栏【File】->设置【Settiings】或快捷键【CtrlAltS】,弹窗的左侧导航树,选择【plugins】,在marketplace 搜索【Continue】,点…...
Windows 10 ARM工控主板CAN总线实时性能测试
在常规的Windows系统中支持CAN总线应用,需要外接CAN总线适配器,通常为USB转CAN模块或PCI接口CAN卡。实时性本身是CAN总线的显著特性之一,但由于Windows并非实时操作系统,应用程序容易受到系统CPU负载影响,导致调度周期…...
深入理解无锁队列与C++原子操作
文章目录 深入理解无锁队列与C原子操作引言原子操作基础什么是原子操作?内存顺序(Memory Order) 无锁队列实现环形缓冲区队列(单生产者/单消费者)链表式无锁队列(多生产者/多消费者) 关键问题与…...
OpenGL: QOpenGLShaderProgram
一、QOpenGLShaderProgram 编译过程的封装 1、bool addShaderFromSourceCode(QGLShader::ShaderType type, const char * source); 2、bool addShaderFromSourceFile(QGLShader::ShaderType type, const QString & fileName); 3、virtual bool link(); 4、bool bind(); 5、…...
【网络编程】之数据链路层
【网络编程】之数据链路层 数据链路层基本介绍基本功能常见协议 以太网什么是以太网以太网协议帧格式数据链路层的以太网帧报文如何封装/解封装以及分用以太网通信原理传统的以太网与集线器现代以太网与交换机碰撞域的概念 Mac地址基本概念为什么要使用Mac地址而不是使用IP地址…...
HTTP 和 TCP/IP-傻傻分不清
HTTP 和 TCP/IP 是计算机网络中不同层次的协议,它们的核心区别在于功能和所属的网络层次。以下是详细对比: 1. 所属网络层次 TCP/IP 定位:TCP/IP 是一个协议族(包含多个协议),涵盖网络通信的传输层和网络层…...
【SQL】SQL约束
🎄约束 📢作用:是用于限制存储再表中的数据。可以再创建表/修改表时添加约束。 📢目的:保证数据库中数据的正确、有效性和完整性。 📢对于一个字段可以同时添加多个约束。 🎄常用约束: 约束分类 约束 描述关键字非…...
【ISO 14229-1:2023 UDS诊断(ECU复位0x11服务)测试用例CAPL代码全解析⑧】
ISO 14229-1:2023 UDS诊断【ECU复位0x11服务】_TestCase08 作者:车端域控测试工程师 更新日期:2025年02月17日 关键词:UDS诊断协议、ECU复位服务、0x11服务、ISO 14229-1:2023 TC11-008测试用例 用例ID测试场景验证要点参考条款预期结果TC…...
解决vue-awesome-swiper 4.x + swiper 5.x 分页pagination配置不生效问题
这次给的需求需要实现几个轮播图,我打算用swiper来做。刚开始我参照同事之前实现的swiper,复制到我的新页面中,是可用的。但是这次的需求需要有底下的分页pagination,而且因为版本比较老,比较难找到配置项。这里说一下…...
Spring Boot 开发入门
文章来源:开发您的第一个 Spring Boot 应用程序 (Developing Your First Spring Boot Application) _ Spring Boot3.4.0中文文档(官方文档中文翻译)|Spring 教程 —— CADN开发者文档中心 本节介绍如何开发一个小型的 “Hello World!” Web 应用程序&…...
MATLAB算法实战应用案例精讲-【数模应用】空间插值(附MATLAB、R语言和python代码实现)
目录 前言 算法原理 什么是插值? 为什么要插值? 常见插值方法 插值方法选择 GIS中常用的空间分析方法 一、空间插值 二、缓冲区分析 三、空间统计 四、领域分析 五、网络分析 六、多标准决策 插值分析 插值应用示例 空间插值的类型 不同工具箱中的空间插值工…...
碰一碰发视频@技术原理与实现开发步骤
碰一碰发视频系统:技术原理与实现方案解析 引言 近年来,随着移动支付和近场通信技术(NFC)的普及,“碰一碰”功能逐渐成为商家与用户交互的新入口。通过“碰一碰加盟”模式,企业可以快速赋能线下商户&…...
14.学成在线开发小结
1.统计两张表的数据,表1和表2是一对多的关系,如果既要统计表1又要统计表2的数据,要分开进行统计,否则表1一条数据在表2中可能有多条数据对应,导致表1的数据被多次统计。 2.nacos配置文件的数据读取不到可能原因有&…...
图像处理之CSC
CSC 是 Color Space Conversion(色彩空间转换)的缩写,它涉及图像处理中的亮度、饱和度、对比度和色度等参数的调整。这些参数是图像处理中的核心概念,通常用于描述和操作图像的颜色信息。 以下是亮度、饱和度、对比度和色度与 CS…...
数据结构:顺序表(Sequence List)及其实现
什么是顺序表? 顺序表是一种最简单的数据结构,它就像一排连续的小房子,每个房子里都住着一个数据元素。这些房子是按顺序排列的,每个房子都有一个门牌号(下标),我们可以通过门牌号快速找到对应…...
微信云开发小程序音频播放踩坑记录 - 从熄屏播放到iOS静音
在开发小程序冥想功能时,我们遇到了几个棘手的问题:用户反馈手机熄屏后音频停止、iOS设备播放没声音、冥想音频没有访问计数和CDN缓存优化等。本文将分享这些问题的解决过程和实践经验。 微信小程序简称:Moodo 微信小程序全程:AIMoodo心情日记系统 简…...
Python基础
https://www.w3schools.com/https://docs.python.org/3/ Python 介绍 Python是跨平台的,它可以运行在Windows、Mac和各种Linux/Unix系统上。在Windows上写Python程序,放到Linux上也是能够运行的。 要开始学习Python编程,首先就得把Python安装…...
基于Go语言 XTA AI聊天界面实现
项目开源地址: XTA-AI-SDK 人工智能技术的迅速发展,AI聊天应用变得越来越流行。本文将介绍如何使用Go语言和LCL库( Lazarus Component Library)创建一个功能丰富的AI聊天界面。项目主要包含以下模块: 项目背景 本项目旨在为开发…...
线上项目报错OOM常见原因、排查方式、解决方案
概述 OutOfMemoryError(OOM)是 Java 应用程序中常见的问题,通常是由于应用程序占用的内存超过了 JVM 分配的最大内存限制。在 Spring Boot 项目中,OOM 问题可能由多种原因引起。 1. OOM 的常见原因 OOM 通常由以下几种情况引起&…...
AI大模型零基础学习(6):多模态大模型实战——让AI看懂世界
从“文字交互”到“全感官认知”的维度突破 一、多模态大模型:AI的“五感觉醒” 1.1 基础概念重塑 单模态局限:传统大模型仅处理文本(如ChatGPT) 多模态进化: 输入:支持文本、图像、音频、视频、3D模型 …...
基于Spring Boot+Vue的宠物服务管理系统(源码+文档)
项目简介 宠物服务管理系统实现了以下功能: 基于Spring BootVue的宠物服务管理系统的主要使用者分为用户管理模块,由于系统运行在互联网络中,一些游客或者病毒恶意进行注册,产生大量的垃圾用户信息,管理员可以对这些…...
简要分析LeetCode树经典题目(Java)
目录 开场白 实战环节 准备工作 遍历问题 LeetCode144. 二叉树的前序遍历 方法一 方法二 LeetCode94. 二叉树的中序遍历 LeetCode145. 二叉树的后序遍历 方法一 方法二 LeetCode102. 二叉树的层序遍历 LeetCode103. 二叉树的锯齿形层序遍历 LeetCode107. 二叉树的…...
vue3开发打年兽功能
1.效果 WeChat_20250217192041 2.代码 2.1 index.vue <template><div class"pages"><TopNavigationYleftTitle"打年兽"ruleIconColor"#fff"backgroundImage""svgIpcn"backIcon4"gradientBackgroundColor&q…...
动手学Agent——Day2
文章目录 一、用 Llama-index 创建 Agent1. 测试模型2. 自定义一个接口类3. 使用 ReActAgent & FunctionTool 构建 Agent 二、数据库对话 Agent1. SQLite 数据库1.1 创建数据库 & 连接1.2 创建、插入、查询、更新、删除数据1.3 关闭连接建立数据库 2. ollama3. 配置对话…...
如何在 GitHub 中创建一个空目录 ?
GitHub 是开发人员必不可少的工具,它提供了存储、共享和协作代码的平台。一个常见的问题是如何在 GitHub 存储库中创建一个空目录或文件夹。GitHub 不支持直接创建空目录。但是,有一种解决方法是使用一个虚拟文件,通常是一个 .gitkeep 文件。…...
3. 导入官方dashboard
官方dashboard:https://grafana.com/grafana/dashboards 1. 点击仪表板 - 新建 - 导入 注:有网络的情况想可以使用ID,无网络情况下使用仪表板josn文件 2. 在官方dashboard网页上选择符合你现在数据源的dashboard - 点击进入 3. 下拉网页选…...
前端知识速记--HTML篇:HTML5的新特性
前端知识速记–HTML篇:HTML5的新特性 一、语义化标签 HTML5引入了许多新的语义化标签,如 <header>、<footer>、<article>、<section> 等。这些标签不仅提高了网页的可读性和结构性,还有助于SEO(搜索引擎…...
【数据分享】1929-2024年全球站点的逐年降雪深度数据(Shp\Excel\免费获取)
气象数据是在各项研究中都经常使用的数据,气象指标包括气温、风速、降水、能见度等指标,说到气象数据,最详细的气象数据是具体到气象监测站点的数据! 有关气象指标的监测站点数据,之前我们分享过1929-2024年全球气象站…...
鸿蒙面试题
1.0penHarmony的系统架构是怎样的? 2.电话服务的框架? 3.OpenHarmony与HarmonyOS有啥区别?...
pdf-extract-kit paddle paddleocr pdf2markdown.py(效果不佳)
GitHub - opendatalab/PDF-Extract-Kit: A Comprehensive Toolkit for High-Quality PDF Content Extraction https://github.com/opendatalab/PDF-Extract-Kit pdf2markdown.py 运行遇到的问题: 错误: -------------------------------------- C Tra…...
基于STM32、HAL库、RX8025T(I2C接口)驱动程序设计
一、简介: RX8025T 是一款低功耗、高精度的实时时钟芯片,具有以下特性: I2C 接口通信 内置 32.768 kHz 晶振 提供秒、分、时、日、月、年等时间信息 支持温度补偿,提高时间精度 低功耗设计,适合电池供电的应用 二、I2C初始化: #include "stm32l4xx_hal.h&…...
基于Ubuntu+vLLM+NVIDIA T4高效部署DeepSeek大模型实战指南
一、 前言:拥抱vLLM与T4显卡的强强联合 在探索人工智能的道路上,如何高效地部署和运行大型语言模型(LLMs)一直是一个核心挑战。尤其是当我们面对资源有限的环境时,这个问题变得更加突出。原始的DeepSeek-R1-32B模型虽…...
【Go语言快速上手】第二部分:Go语言进阶之并发编程
文章目录 一、并发编程1. goroutine:创建和调度 goroutine2. channel:无缓冲 channel、有缓冲 channel、select 语句2.1 无缓冲 channel2.2 有缓冲 channel2.3 select 语句 3. sync 包:Mutex、RWMutex、WaitGroup 等同步原语3.1 Mutex&#x…...
《机器学习数学基础》补充资料:四元数、点积和叉积
《机器学习数学基础》第1章1.4节介绍了内积、点积的有关概念,特别辨析了内积空间、欧几里得空间;第4章4.1.1节介绍了叉积的有关概念;4.1.2节介绍了张量积(也称外积)的概念。 以上这些内容,在不同资料中&…...