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

C++多线程与锁机制

1. 基本多线程编程

1.1 创建线程

#include <iostream>
#include <thread>void thread_function() {std::cout << "Hello from thread!\n";
}int main() {std::thread t(thread_function); // 创建并启动线程t.join(); // 等待线程结束return 0;
}

1.2 带参数的线程函数

#include <thread>
#include <iostream>void print_num(int num) {std::cout << "Number: " << num << "\n";
}int main() {std::thread t(print_num, 42);t.join();return 0;
}

1.3 join() 和 detach()

std::thread t(threadFunction);// join() - 等待线程完成
t.join();// detach() - 分离线程,线程独立运行
// t.detach();// 检查线程是否可joinable
if (t.joinable()) {t.join();
}

 1.4 获取当前线程信息

#include <thread>
#include <iostream>int main() {std::cout << "Main thread ID: " << std::this_thread::get_id() << std::endl;std::thread t([](){std::cout << "Worker thread ID: " << std::this_thread::get_id() << std::endl;});t.join();return 0;
}

 1.5 线程休眠

#include <chrono>
#include <thread>int main() {std::cout << "Sleeping for 2 seconds..." << std::endl;std::this_thread::sleep_for(std::chrono::seconds(2));std::cout << "Awake!" << std::endl;return 0;
}

2. mutex (互斥锁)

#include <thread>
#include <mutex>
#include <iostream>std::mutex mtx; // 全局互斥锁
int shared_data = 0;void increment() {for (int i = 0; i < 100000; ++i) {mtx.lock();   // 上锁++shared_data;mtx.unlock(); // 解锁}
}int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();std::cout << "Final value: " << shared_data << "\n";return 0;
}

2.1 lock_guard (自动管理锁)

lock_guard 在构造时自动上锁,在析构时自动解锁,防止忘记解锁

void increment_safe() {for (int i = 0; i < 100000; ++i) {std::lock_guard<std::mutex> lock(mtx); // 自动上锁++shared_data;} // 自动解锁
}

2.2 unique_lock

unique_lock 比 lock_guard 更灵活,可以手动上锁和解锁。

void increment_flexible() {for (int i = 0; i < 100000; ++i) {std::unique_lock<std::mutex> lock(mtx);++shared_data;lock.unlock(); // 可以手动解锁// 做一些不需要锁的操作lock.lock();   // 再手动上锁++shared_data;}
}

2.3 尝试锁 try_lock()

void tryLockExample() {std::unique_lock<std::mutex> lock(mtx, std::try_to_lock);if (lock.owns_lock()) {// 成功获取锁std::cout << "Got the lock!\n";} else {// 未能获取锁std::cout << "Couldn't get the lock, doing something else...\n";}
}

 2.4 递归互斥锁 std::recursive_mutex

#include <mutex>std::recursive_mutex rec_mtx;void recursiveFunction(int count) {std::lock_guard<std::recursive_mutex> lock(rec_mtx);if (count > 0) {std::cout << "Count: " << count << '\n';recursiveFunction(count - 1);}
}int main() {std::thread t(recursiveFunction, 3);t.join();return 0;
}

2.5 定时互斥锁 std::timed_mutex 

#include <mutex>
#include <chrono>std::timed_mutex timed_mtx;void timedLockExample() {auto timeout = std::chrono::milliseconds(100);if (timed_mtx.try_lock_for(timeout)) {// 在100ms内成功获取锁std::this_thread::sleep_for(std::chrono::milliseconds(50));timed_mtx.unlock();} else {// 超时未能获取锁std::cout << "Could not get the lock within 100ms\n";}
}

2.6 std::adopt_lock与std::defer_lock

特性std::adopt_lockstd::defer_lock
用途表示锁已被当前线程获得表示不立即获取锁
加锁时机不尝试加锁(假设已锁定)稍后手动加锁
典型使用场景与 std::lock 配合使用延迟加锁或条件加锁
可用性适用于 lock_guard 和 unique_lock仅适用于 unique_lock

 adopt_lock表示当前线程已经获得了互斥锁的所有权,不需要再尝试加锁

#include <mutex>std::mutex mtx;void function() {mtx.lock(); // 手动加锁// 使用 adopt_lock 告诉 lock_guard 我们已经拥有锁std::lock_guard<std::mutex> lock(mtx, std::adopt_lock);// 临界区代码...// 离开作用域时自动解锁
}

3. 条件变量 (condition_variable)

用于线程间的同步,允许线程等待特定条件成立。

#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>std::mutex mtx;
std::condition_variable cv;
bool ready = false;void worker() {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, []{ return ready; }); // 等待ready变为truestd::cout << "Worker is processing data\n";
}int main() {std::thread t(worker);{std::lock_guard<std::mutex> lock(mtx);ready = true;}cv.notify_one(); // 通知等待的线程t.join();return 0;
}

3.1 wait

std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock); // 无条件等待,可能虚假唤醒

 带谓词的 wait()

cv.wait(lock, []{ return ready; }); // 等价于:
// while (!ready) {
//     cv.wait(lock);
// }

wait_for() - 带超时等待

using namespace std::chrono_literals;
if (cv.wait_for(lock, 100ms, []{ return ready; })) {// 条件在超时前满足
} else {// 超时
}

wait_until() - 等待到指定时间点

auto timeout = std::chrono::steady_clock::now() + 100ms;
if (cv.wait_until(lock, timeout, []{ return ready; })) {// 条件在时间点前满足
} else {// 超时
}

3.2 notify

notify_one() - 通知一个等待线程

{std::lock_guard<std::mutex> lock(mtx);ready = true;
}
cv.notify_one(); // 只唤醒一个等待线程

notify_all() - 通知所有等待线程

{std::lock_guard<std::mutex> lock(mtx);ready = true;
}
cv.notify_all(); // 唤醒所有等待线程

3.3 生产消费者模式示例

#include <queue>
#include <chrono>std::mutex mtx;
std::condition_variable cv;
std::queue<int> data_queue;
const int MAX_SIZE = 10;void producer() {for (int i = 0; i < 20; ++i) {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, []{ return data_queue.size() < MAX_SIZE; });data_queue.push(i);std::cout << "Produced: " << i << std::endl;lock.unlock();cv.notify_all();std::this_thread::sleep_for(std::chrono::milliseconds(100));}
}void consumer() {while (true) {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, []{ return !data_queue.empty(); });int data = data_queue.front();data_queue.pop();std::cout << "Consumed: " << data << std::endl;lock.unlock();cv.notify_all();if (data == 19) break; // 结束条件}
}int main() {std::thread p(producer);std::thread c(consumer);p.join();c.join();return 0;
}

4. 原子操作 (atomic)

对于简单的数据类型,可以使用原子操作避免锁的开销。

#include <atomic>
#include <thread>
#include <iostream>std::atomic<int> counter(0);void increment_atomic() {for (int i = 0; i < 100000; ++i) {++counter; // 原子操作,无需锁}
}int main() {std::thread t1(increment_atomic);std::thread t2(increment_atomic);t1.join();t2.join();std::cout << "Counter: " << counter << "\n";return 0;
}

4.1 基本原子类型

#include <atomic>std::atomic<int> atomicInt(0);      // 原子整数
std::atomic<bool> atomicBool(false); // 原子布尔值
std::atomic<long> atomicLong;       // 默认初始化为0

4.2 加载和存储

// 存储值
atomicInt.store(42);                // 原子存储
atomicInt = 42;                     // 等价写法// 加载值
int value = atomicInt.load();       // 原子加载
value = atomicInt;                  // 等价写法

4.3 交换操作

int old = atomicInt.exchange(100);  // 原子交换为新值,返回旧值

4.4 读-修改-写操作

std::atomic<int> counter(0);// 原子加法,返回旧值
int prev = counter.fetch_add(5);    // counter += 5,返回加前的值// 原子减法
prev = counter.fetch_sub(3);       // counter -= 3,返回减前的值
std::atomic<int> flags(0);flags.fetch_or(0x01);   // 原子按位或
flags.fetch_and(~0x01); // 原子按位与
flags.fetch_xor(0x03);  // 原子按位异或

4.5 比较交换 (CAS) 

std::atomic<int> value(10);
int expected = 10;// 比较并交换
bool success = value.compare_exchange_weak(expected, 20);
// 如果value == expected,则设置为20,返回true
// 否则将expected更新为当前value,返回false// 强版本 (较少虚假失败)
success = value.compare_exchange_strong(expected, 30);

 4.6 内存顺序 (Memory Order)

// 默认是最严格的内存顺序 (sequential consistency)
atomicInt.store(42, std::memory_order_seq_cst);// 宽松内存顺序
atomicInt.store(42, std::memory_order_relaxed);// 常见内存顺序:
// - memory_order_relaxed: 无顺序保证
// - memory_order_consume: 数据依赖顺序
// - memory_order_acquire: 读操作,防止上方读写重排
// - memory_order_release: 写操作,防止下方读写重排
// - memory_order_acq_rel: 读-修改-写操作
// - memory_order_seq_cst: 顺序一致性 (默认)

4.7 原子标志

std::atomic_flag flag = ATOMIC_FLAG_INIT; // 必须这样初始化// 测试并设置 (原子操作)
bool was_set = flag.test_and_set();// 清除标志
flag.clear();

4.8 原子指针

class MyClass {};
MyClass* ptr = new MyClass();
std::atomic<MyClass*> atomicPtr(ptr);// 原子指针操作
MyClass* old = atomicPtr.exchange(new MyClass());// 比较交换指针
MyClass* expected = old;
atomicPtr.compare_exchange_strong(expected, nullptr);

4.9 自定义原子类型

struct Point { int x; int y; };
std::atomic<Point> atomicPoint{Point{1, 2}};// 必须是可平凡复制的类型(trivially copyable)
static_assert(std::is_trivially_copyable<Point>::value, "Point must be trivially copyable");
// 原子操作示例
Point old = atomicPoint.load();          // 原子读取
atomicPoint.store(Point{3, 4});         // 原子写入
Point newVal{5, 6};
Point expected{3, 4};
atomicPoint.compare_exchange_strong(expected, newVal); // CAS操作

std::atomic 对模板类型 T 的关键要求是:

  • 可平凡复制(Trivially Copyable):保证对象可以用 memcpy 方式安全复制

  • 无用户定义的拷贝控制(析构函数、拷贝/移动构造/赋值)

  • 标准布局(Standard Layout)

static_assert 在编译时验证这些条件,若不满足会立即报错(比运行时错误更安全)。

 一个类型 T 是 平凡可复制(Trivially Copyable) 的,当且仅当满足以下所有条件:

  1. 没有用户定义的拷贝构造函数(T(const T&)

  2. 没有用户定义的移动构造函数(T(T&&)

  3. 没有用户定义的拷贝赋值运算符(T& operator=(const T&)

  4. 没有用户定义的移动赋值运算符(T& operator=(T&&)

  5. 有一个平凡的(隐式定义的或 =default)析构函数

  6. 所有非静态成员和基类也必须是平凡可复制的

  7. 不能有虚函数或虚基类

如果满足这些条件,编译器可以安全地使用 memcpy 来复制该类型的对象,而不会引发未定义行为(UB)。

5. 死锁预防

当多个线程需要多个锁时,可能产生死锁。预防方法:

  1. 总是以相同的顺序获取锁

  2. 使用 std::lock 同时锁定多个互斥量

std::mutex mtx1, mtx2;void safe_lock() {// 同时锁定两个互斥量,避免死锁std::lock(mtx1, mtx2);std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);// 安全地访问共享资源
}

6. 线程局部存储 (thread_local)

使用 thread_local 关键字声明线程局部变量,每个线程有自己的副本。

#include <thread>
#include <iostream>thread_local int thread_specific_value = 0;void thread_function(int id) {thread_specific_value = id;std::cout << "Thread " << id << ": " << thread_specific_value << "\n";
}int main() {std::thread t1(thread_function, 1);std::thread t2(thread_function, 2);t1.join();t2.join();return 0;
}

7. 读写锁

读写锁是一种特殊的同步机制,允许多个读操作并发执行,但写操作必须独占访问。这种锁在"读多写少"的场景下能显著提高性能。

C++17 中的 std::shared_mutex

#include <shared_mutex>
#include <vector>class ThreadSafeContainer {
private:std::vector<int> data;mutable std::shared_mutex mutex; // mutable 允许const方法加锁public:// 读操作 - 使用共享锁int get(size_t index) const {std::shared_lock<std::shared_mutex> lock(mutex);return data.at(index);}// 写操作 - 使用独占锁void set(size_t index, int value) {std::unique_lock<std::shared_mutex> lock(mutex);data.at(index) = value;}// 批量读操作示例std::vector<int> getSnapshot() const {std::shared_lock<std::shared_mutex> lock(mutex);return data;}
};

读写锁特性

  1. 三种访问模式

    • 共享读锁 (shared_lock):多个线程可同时持有

    • 独占写锁 (unique_lock):只有一个线程可持有

    • 升级锁 (C++14没有直接支持,需手动实现)

  2. 锁的优先级策略

    • 读优先:容易导致写线程饥饿

    • 写优先:可能降低读并发度

    • 公平策略:折中方案

  3. 典型使用场景

    • 配置信息的热更新

    • 缓存系统

    • 高频查询低频修改的数据结构

8. 自旋锁 (Spin Lock)

自旋锁是一种非阻塞锁,当线程无法获取锁时不会休眠,而是循环检查锁状态(忙等待)。适用于锁持有时间极短的场景。 

基本自旋锁实现

#include <atomic>class SpinLock {std::atomic_flag flag = ATOMIC_FLAG_INIT;public:void lock() {while(flag.test_and_set(std::memory_order_acquire)) {// 可加入CPU暂停指令减少争用时的能耗#ifdef __x86_64____builtin_ia32_pause();#endif}}void unlock() {flag.clear(std::memory_order_release);}bool try_lock() {return !flag.test_and_set(std::memory_order_acquire);}
};

 TTAS + Backoff

class AdvancedSpinLock {std::atomic<bool> locked{false};public:void lock() {bool expected = false;int backoff = 1;const int max_backoff = 64;while(!locked.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_relaxed)) {expected = false; // compare_exchange_weak会修改expected// 指数退避for(int i = 0; i < backoff; ++i) {#ifdef __x86_64____builtin_ia32_pause();#endif}backoff = std::min(backoff * 2, max_backoff);}}void unlock() {locked.store(false, std::memory_order_release);}
};

相关文章:

C++多线程与锁机制

1. 基本多线程编程 1.1 创建线程 #include <iostream> #include <thread>void thread_function() {std::cout << "Hello from thread!\n"; }int main() {std::thread t(thread_function); // 创建并启动线程t.join(); // 等待线程结束return 0; …...

【MCP Node.js SDK 全栈进阶指南】高级篇(4):自定义传输层开发

引言 在MCP(Model Context Protocol)应用开发中,传输层是连接客户端与服务器的关键环节,直接影响应用的性能、可靠性和扩展性。默认的传输方式虽然能满足基本需求,但在复杂场景下,自定义传输层能够为应用提供更高的灵活性和优化空间。本文将深入探讨MCP TypeScript-SDK中…...

当向量数据库与云计算相遇:AI应用全面提速

如果将AI比作一台高速运转的机器引擎&#xff0c;那么数据便是它的燃料。 然而&#xff0c;存储数据的燃料库--传统数据库&#xff0c;在AI时代的效率瓶颈愈发明显&#xff0c;已经无法满足AI对于数据的全新需求。 因此&#xff0c;向量数据库近年来迅速崛起。向量数据库通过…...

【2024-NIPS-版权】Evaluating Copyright Takedown Methods for Language Models

1.背景 目前 LLMs 在训练过程中使用了大量的受版权保护数据&#xff0c;这些数据会导致大模型记忆并生成与训练数据相似的内容&#xff0c;从而引发版权问题。随着版权所有者对模型训练和部署中的版权问题提起诉讼&#xff08;例如 Tremblay v. OpenAI, Inc. 和 Kadrey v. Met…...

【PyTorch动态计算图原理精讲】从入门到灵活应用

目录 前言技术背景与价值当前技术痛点解决方案概述目标读者说明一、技术原理剖析核心概念图解核心作用讲解关键技术模块说明技术选型对比二、实战演示环境配置要求核心代码实现案例1:基础计算图构建案例2:条件分支动态图案例3:循环结构动态图运行结果验证三、性能对比测试方…...

阿里巴巴Qwen3发布:登顶全球开源模型之巅,混合推理模式重新定义AI效率

今天凌晨&#xff0c;阿里巴巴正式开源了新一代通义千问大模型Qwen3&#xff0c;这一举措不仅标志着国产大模型技术的又一里程碑&#xff0c;更以“混合推理”“极致性能”“超低成本”三大核心优势&#xff0c;刷新了全球开源模型的竞争格局。Qwen3在多项评测中超越DeepSeek-R…...

5. 配置舵机ID(具身智能机器人套件)

1. 连接舵机 waveshare驱动器板使用9-12v供电Type-C连接电脑DVG连接一个舵机 2. 使用FT SCServo Debug软件 设置串口设置波特率&#xff08;默认1000000&#xff0c;100万&#xff09;打开串口编程界面修改ID 3. 依次修改所有舵机ID 分别使用waveshare驱动板连接舵机&…...

Nacos源码—2.Nacos服务注册发现分析四

大纲 5.服务发现—服务之间的调用请求链路分析 6.服务端如何维护不健康的微服务实例 7.服务下线时涉及的处理 8.服务注册发现总结 7.服务下线时涉及的处理 (1)Nacos客户端服务下线的源码 (2)Nacos服务端处理服务下线的源码 (3)Nacos服务端发送服务变动事件给客户端的源码…...

从Windows开发迁移到信创开发的指南:国产替代背景下的技术路径与实践

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;10年以上C/C, C#, Java等多种编程语言开发经验&#xff0c;拥有高级工程师证书&#xff1b;擅长C/C、C#等开发语言&#xff0c;熟悉Java常用开…...

从数据到决策:安科瑞EIoT如何让每一度电“清晰可见”?

安科瑞顾强 在能源管理迈向精细化与数字化的今天&#xff0c;安科瑞EIoT能源物联网平台以“数据驱动能源价值”为核心理念&#xff0c;融合物联网、云计算与大数据技术&#xff0c;打通从设备感知到云端决策的全链路闭环&#xff0c;助力工商业企业、园区、物业等场景实现用电…...

10.学习笔记-MyBatisPlus(P105-P110)

1.MyBatisPlus入门案例 &#xff08;1&#xff09;MyBatisPlus&#xff08;简称Mp&#xff09;是基于MyBatis框架基础上开发的增强型工具&#xff0c;目的是简化开发&#xff0c;提高效率。 &#xff08;2&#xff09;开发方式&#xff1a;基于MyBatis使用MyBatisPlus&#xff…...

LayerSkip: Enabling Early Exit Inference and Self-Speculative Decoding

TL;DR 2024 年 Meta FAIR 提出了 LayerSkip&#xff0c;这是一种端到端的解决方案&#xff0c;用于加速大语言模型&#xff08;LLMs&#xff09;的推理过程 Paper name LayerSkip: Enabling Early Exit Inference and Self-Speculative Decoding Paper Reading Note Paper…...

fastapi和flaskapi有什么区别

FastAPI 和 Flask 都是 Python 的 Web 框架&#xff0c;但设计目标和功能特性有显著差异。以下是它们的核心区别&#xff1a; 1. ‌性能与异步支持‌ ‌FastAPI‌ 基于 ‌Starlette‌&#xff08;高性能异步框架&#xff09;和 ‌Pydantic‌&#xff08;数据校验库&#xff09;…...

在 JMeter 中使用 BeanShell 获取 HTTP 请求体中的 JSON 数据

在 JMeter 中&#xff0c;您可以使用 BeanShell 处理器来获取 HTTP 请求体中的 JSON 数据。以下是几种方法&#xff1a; 方法一&#xff1a;使用前置处理器获取请求体 如果您需要在发送请求前访问请求体&#xff1a; 添加一个 BeanShell PreProcessor 到您的 HTTP 请求采样器…...

Go 1.25为什么要废除核心类型

​​​​​​​关于核心类型为什么要1.25里要移除&#xff0c;作者Robert在博客Goodbye core types - Hello Go as we know and love it!​​​​​​​里给了详细耐心的解答。 背景&#xff1a;Go 1.18 引入了泛型&#xff08;generics&#xff09;&#xff0c;带来了类型参数…...

flask中的Response 如何使用?

在 Flask 中&#xff0c;Response 对象用于生成 HTTP 响应并返回给客户端。以下是其常见用法及示例&#xff1a; 1. 直接返回字符串或 HTML 视图函数返回的字符串会被自动包装为 Response 对象&#xff0c;默认状态码为 200&#xff0c;内容类型为 text/html&#xff1a; app…...

基于SpringAI实现简易聊天对话

简介 本文旨在记录学习和实践 Spring AI Alibaba 提供的 ChatClient 组件的过程。ChatClient 是 Spring AI 中用于与大语言模型&#xff08;LLM&#xff09;进行交互的高级 API&#xff0c;它通过流畅&#xff08;Fluent&#xff09;的编程接口&#xff0c;极大地简化了构建聊天…...

STM32单片机入门学习——第49节: [15-2] 读写内部FLASH读取芯片ID

写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难&#xff0c;但我还是想去做&#xff01; 本文写于&#xff1a;2025.04.29 STM32开发板学习——第49节: [15-2] 读写内部FLASH&读取芯片ID 前言开发板说…...

第14讲:科研图表的导出与排版艺术——高质量 PDF、TIFF 输出与投稿规范全攻略!

目录 📘 前言:导出,不只是“保存”! 🎯 一、你需要掌握的导出目标 🖼️ 二、TIFF / PNG 导出规范(适用于投稿) 🧲 三、PDF 矢量图导出(排版首选) 🧩 四、强烈推荐组合:showtext + Cairo 🧷 五、多个图的组合导出技巧 🧪 六、特殊投稿需求处理 �…...

SRIO IP调试问题记录(ready信号不拉高情况)

问题&#xff1a;调试过程中遇到有时写入数据后数据不发送&#xff0c;并且ready信号在写入一定数据后一直拉低的情况&#xff08;偶发&#xff0c;不是每次必然出现&#xff09;。buf空间设置为16时&#xff0c;写入15包数据&#xff0c;写完第16包包头后&#xff0c;ready信号…...

使用DDR4控制器实现多通道数据读写(十)

一、本章概述 本章节对目前单通道的读写功能进项测试&#xff0c;主要验证读写的数据是否正确&#xff0c;并观察该工程可以存储的最大容量。通过空满信号进行读写测试&#xff0c;根据ila抓取fifo和ddr4全部满的时刻&#xff0c;可以观察到最大容量。再通过debug逻辑可以测试读…...

从 BERT 到 GPT:Encoder 的 “全局视野” 如何喂饱 Decoder 的 “逐词纠结”

当 Encoder 学会 “左顾右盼”&#xff1a;Decoder 如何凭 “单向记忆” 生成丝滑文本&#xff1f; 目录 当 Encoder 学会 “左顾右盼”&#xff1a;Decoder 如何凭 “单向记忆” 生成丝滑文本&#xff1f;引言一、Encoder vs Decoder&#xff1a;核心功能与基础架构对比1.1 本…...

探寻软件稳定性的奥秘

在软件开发的广袤领域中&#xff0c;软件的稳定性宛如基石&#xff0c;支撑着整个软件系统的运行与发展。《发布&#xff01;软件的设计与部署》这本书的第一部分&#xff0c;对软件稳定性进行了深入且全面的剖析&#xff0c;为软件开发人员、架构师以及相关从业者们提供了极具…...

Reverse-WP记录9

前言 之前写的&#xff0c;一直没发&#xff0c;留个记录吧&#xff0c;万一哪天记录掉了起码在csdn有个念想 1.easyre1 32位无壳elf文件 shiftF12进入字符串&#xff0c;发现一串数字&#xff0c;双击进入 进入main函数 int __cdecl main(int argc, const char **argv, const…...

日常开发小Tips:后端返回带颜色的字段给前端

一般来说&#xff0c;展示给用户的字体格式&#xff0c;都是由前端控制&#xff0c;展现给用户&#xff1b; 但是当要表示某些字段的数据为异常数据&#xff0c;或者将一些关键信息以不同颜色的形式呈现给用户时&#xff0c;而前端又不好判断&#xff0c;那么就可以由后端来控…...

partition_pdf 和chunk_by_title 的区别

from unstructured.partition.pdf import partition_pdf from unstructured.chunking.title import chunk_by_titlepartition_pdf 和 chunk_by_title 初看有点像&#xff0c;都在"分块"&#xff0c;但是它们的本质完全不一样。 先看它们核心区别 partition_pdfchun…...

JAVA-使用Apache POI导出数据到Excel,并把每条数据的图片打包成zip附件项

最近项目要实现一个功能&#xff0c;就是在导出报表的时候 &#xff0c;要把每条数据的所有图片都要打包成zip附件在excel里一起导出。 1. 添加依赖 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>…...

前端——CSS1

一&#xff0c;概述 CSS&#xff08;Cascading Style Sheets&#xff09;&#xff08;级联样式表&#xff09; css是一种样式表语言&#xff0c;为html标签修饰定义外观&#xff0c;分工不同 涉及&#xff1a;对网页的文字、背景、宽、高、布局进行修饰 分为内嵌样式表&…...

《AI大模型应知应会100篇》【精华】第40篇:长文本处理技巧:克服大模型的上下文长度限制

[精华]第40篇&#xff1a;长文本处理技巧&#xff1a;克服大模型的上下文长度限制 摘要 在大语言模型应用中处理超出其上下文窗口长度的长文本是一项挑战。本文面向初学者介绍长文本处理的常见难题&#xff0c;以及一系列有效策略和技巧&#xff0c;包括如何对文档进行合理分…...

开源模型应用落地-qwen模型小试-Qwen3-8B-快速体验(一)

一、前言 阿里云最新推出的 Qwen3-8B 大语言模型,作为国内首个集成“快思考”与“慢思考”能力的混合推理模型,凭借其 80 亿参数规模及 128K 超长上下文支持,正在重塑 AI 应用边界。该模型既可通过轻量化“快思考”实现低算力秒级响应,也能在复杂任务中激活深度推理模式,以…...

千问3(Qwen3)模型开源以及初体验

体验地址&#xff1a;百炼控制台 1 千问3模型&#xff1a;全球最强开源大模型震撼发布 2025年4月29日&#xff0c;阿里巴巴正式开源了新一代通义千问模型Qwen3&#xff08;简称千问3&#xff09;&#xff0c;这一里程碑式的事件标志着中国开源大模型首次登顶全球性能榜首。千问…...

对 FormCalc 语言支持较好的 PDF 编辑软件综述

FormCalc是一种专为PDF表单计算设计的脚本语言&#xff0c;主要应用于Adobe生态及SAP相关工具。以下是对FormCalc支持较好的主流软件及其特点&#xff1a; 1. Adobe LiveCycle Designer 作为FormCalc的原生开发环境&#xff0c;LiveCycle Designer提供最佳支持&#xff1a; …...

20250429-李彦宏口中的MCP:AI时代的“万能接口“

目录 一、什么是MCP&#xff1f; 二、为什么需要MCP&#xff1f; 三、MCP的工作原理 3.1 核心架构 3.2 工作流程 四、MCP的应用场景 4.1 开发者工具集成 4.2 智能助手增强 4.3 企业应用集成 4.4 典型案例 五、MCP的技术特点 5.1 标准化接口 5.2 可扩展性设计 5.…...

汽车启动原理是什么?

好的&#xff01;同学们&#xff0c;今天我们来讨论汽车的启动原理&#xff0c;重点分析其中的动力来源和摩擦力作用。我会结合物理概念&#xff0c;用尽量直观的方式讲解。 1. 汽车为什么会动&#xff1f;——动力的来源 汽车发动机&#xff08;内燃机或电动机&#xff09;工…...

LeetCode[347]前K个高频元素

思路&#xff1a; 使用小顶堆&#xff0c;最小的元素都出去了&#xff0c;省的就是大&#xff0c;高频的元素了&#xff0c;所以要维护一个小顶堆&#xff0c;使用map存元素高频变化&#xff0c;map存堆里&#xff0c;然后输出堆的东西就行了 代码&#xff1a; class Solution…...

《软件测试52讲》学习笔记:如何设计一个“好的“测试用例?

引言 在软件测试领域&#xff0c;设计高质量的测试用例是保证软件质量的关键。本文基于茹炳晟老师在《软件测试52讲》中关于测试用例设计的讲解&#xff0c;结合个人学习心得&#xff0c;系统总结如何设计一个"好的"测试用例。 一、什么是"好的"测试用例…...

【深度学习新浪潮】ISP芯片算法技术简介及关键技术分析

ISP芯片及其功能概述 ISP(Image Signal Processor)芯片作为现代影像系统的核心组件,负责对图像传感器输出的原始信号进行后期处理。ISP的主要功能包括线性纠正、噪声去除、坏点修复、色彩校正以及白平衡调整等,这些处理步骤对于提高图像质量和视觉效果至关重要。随着科技的…...

QtCreator Kits构建套件报错(红色、黄色感叹号)

鼠标移动上去&#xff0c;查看具体报错提示。 一.VS2022Qt5.14.2(MSVC2017) 环境VS2022Qt5.14.2(MSVC2017) 错误&#xff1a;Compilers produce code for different ABIs&#xff1a;x86-windows-msvc2005-pe-64bit&#xff0c;x86-windows-msvc2005-pe-32bit 错误&#xff1…...

天能资管(SkyAi):全球布局,领航资管新纪元

在全球化浪潮汹涌澎湃的今天,资管行业的竞争已不再是单一市场或区域的较量,而是跨越国界、融合全球资源的全面竞争。天能资管(SkyAi),作为卡塔尔投资局(Qatar Investment Authority,QIA)旗下的尖端科技品牌,正以其独特的全球视野和深远的战略眼光,积极布局资管赛道,力求在全球资…...

基于PHP的宠物用品商城

有需要请加文章底部Q哦 可远程调试 基于PHP的宠物用品商城 一 介绍 宠物用品商城系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap&#xff0c;jquery.js等。系统角色分为用户和管理员。(附带参考文档) 技术栈&#xff1a;phpmysqlbootstrapphpstudyvsc…...

桂链:使用Fabric的测试网络

桂链是基于Hyperledger Fabric开源区块链框架扩展开发的区块链存证平台&#xff0c;是桂云网络&#xff08;OSG&#xff09;公司旗下企业供应链、流程审批等场景数字存证软件产品&#xff0c;与桂花流程引擎&#xff08;Osmanthus&#xff09;并列为桂云网络旗下的标准与可定制…...

k8s术语master,node,namepace,LABLE

1.Master Kubernetes中的master指的是集群控制节点,每个kubernetes集群里都需要有一个Master节点来负责整个集群的管理和控制,基本上kubernetes的所有控制命令都发给它,它来负责具体的执行过程。Master节点通常会占据一个独立的服务器(高可用建议3台服务器)。 Master节点…...

香港科技大学广州|智能制造学域硕、博研究生招生可持续能源与环境学域博士招生宣讲会—四川大学专场!

香港科技大学广州&#xff5c;智能制造学域硕、博研究生招生&可持续能源与环境学域博士招生宣讲会—四川大学专场&#xff01;&#xff01;&#xff01; 两个学域代表教授亲临现场&#xff0c;面对面答疑解惑助攻申请&#xff01;可带简历现场咨询和面试&#xff01; &am…...

【Vue】 实现TodoList案例(待办事项)

目录 组件化编码流程&#xff08;通用&#xff09; 1.实现静态组件&#xff1a;抽取组件&#xff0c;使用组件实现静态页面效果 2.展示动态数据&#xff1a; 1. 常规 HTML 属性 3.交互——从绑定事件监听开始 什么时候要用 event&#xff1a; 什么时候不需要用 event&am…...

Ubuntu 20.04 安装 ROS 2 Foxy Fitzroy

目录 1&#xff0c;安装前须知 2&#xff0c;安装过程 2.1&#xff0c;设置语言环境 ​2.2&#xff0c;设置源 ​2.3&#xff0c;安装ROS 2软件包 2.4&#xff0c;​环境设置 ​​2.5&#xff0c;测试 2‍.6&#xff0c;不想每次执行source 检验是否成功&#xff08;另…...

【Unity】使用LitJson保存和读取数据的例子

LitJson 是一个轻量级的 JSON 解析和生成库&#xff0c;广泛应用于 .NET 环境中。 优点&#xff1a;轻量级&#xff0c;易用&#xff0c;性能优秀&#xff0c;支持LINQ和自定义对象的序列化和反序列化。 public class LitJsonTest : MonoBehaviour { // Start is called before…...

飞蛾扑火算法优化+Transformer四模型回归打包(内含MFO-Transformer-LSTM及单独模型)

飞蛾扑火算法优化Transformer四模型回归打包&#xff08;内含MFO-Transformer-LSTM及单独模型&#xff09; 目录 飞蛾扑火算法优化Transformer四模型回归打包&#xff08;内含MFO-Transformer-LSTM及单独模型&#xff09;预测效果基本介绍程序设计参考资料 预测效果 基本介绍 …...

物联网平台厂商有哪些?2025物联网平台推荐?国内有哪些比较好的物联网平台?

评选维度&#xff1a; 技术实力&#xff1a;涵盖设备接入规模、数据处理效率、AI/边缘计算融合能力、协议兼容性及平台架构先进。 应用场景&#xff1a;包括垂直领域解决方案的成熟度、定制化能力、跨行业复用性及实际落地案例规模。 安全可靠&#xff1a;涉及数据传输加密、…...

瑞幸咖啡披露2025年Q1财报:门店净增1757家,营业利润率达8.3%

4月29日&#xff0c;瑞幸咖啡&#xff08;OTC&#xff1a;LKNCY&#xff09;公布2025年第一季度财报。数据显示&#xff0c;2025年第一季度总净收入88.65亿元人民币&#xff0c;同比增长41.2%&#xff0c;GMV达103.54亿元人民币。截止一季度末&#xff0c;门店总数达24097家。依…...

selenium IDE脚本如何转换为可运行的selenium webdriver java程序

上一篇博客&#xff08;用selenium4 webdriver java 搭建并完成第一个自动化测试脚本-CSDN博客&#xff09;介绍了如何创建一个selenium webdriver 的java工程。 之前博客&#xff08;​​​​​​带你用selenium IDE的录制第一个自动化测试脚本也介绍了如何使用selenum ide …...