C++ atomic 原子操作
一、原子操作简介
在多线程编程中,通常我们需要多个线程共享数据。但如果不加以控制,多个线程同时访问同一数据,可能会导致数据不一致或竞争条件(race conditions)。为了解决这个问题,我们引入了 原子操作。
原子操作 是指在执行时不会被中断、打断或修改的操作。换句话说,原子操作要么完全执行,要么完全不执行,不会在中间被其他线程的操作干扰。这种特性对于多线程环境中的数据访问是至关重要的。
C++11 引入了 <atomic>
库,它提供了对原子操作的支持。通过这个库,我们可以确保在多线程环境中对数据的访问不会导致竞争条件。
二、C++ 原子操作的基本概念
在 C++ 中,原子操作的关键是 原子类型(atomic types)。原子类型是由 std::atomic
模板类提供的,它包装了一个类型,确保对该类型的所有操作(如读取、写入、更新等)都是原子的。
关键概念
- 原子类型 (
std::atomic
):可以包装任何基本类型(如int
、bool
、float
等),并保证对这些类型的操作是原子的。 - 原子操作:对原子变量的操作是不可分割的,意味着在多线程中不会被打断。
- 原子变量:一个变量可以被声明为原子类型(如
std::atomic<int>
),它保证在多线程环境下对该变量的操作是安全的。
常用的原子操作
- load:读取原子变量的值。
- store:将一个值存储到原子变量中。
- exchange:将原子变量的值替换为一个新值,并返回旧值。
- compare_exchange_weak / compare_exchange_strong:原子地进行条件交换操作。若当前值等于预期值,则交换新值。
- fetch_add / fetch_sub:原子地执行加法或减法操作,并返回旧值。
三、std::atomic
类模板
std::atomic
是一个模板类,可以用于包装基础数据类型,确保对该数据类型的所有操作都是原子性的。
基本使用
#include <iostream>
#include <atomic>
#include <thread>
#include <vector>
using namespace std;std::atomic<int> counter(0);void increment() {for (int i = 0; i < 100000; ++i) {counter.fetch_add(1, std::memory_order_relaxed); // 原子递增}
}int main() {std::vector<std::thread> threads;for (int i = 0; i < 4; ++i) {threads.push_back(std::thread(increment)); // 启动4个线程}for (auto& t : threads) {t.join(); // 等待线程完成}cout << "Counter value: " << counter.load() << endl; // 输出最终结果return 0;
}
常用原子操作的详细介绍
1. load() 和 store()
load()
:从原子变量读取值。store()
:将值存储到原子变量中。
std::atomic<int> a(10);
int value = a.load(); // 获取原子变量a的值
a.store(20); // 将原子变量a的值设置为20
2. exchange()
exchange
会将原子变量的值更新为给定的值,并返回原先的值。常用来在并发环境下进行“交换”操作。
std::atomic<int> a(5);
int old_value = a.exchange(10); // 将a的值设置为10,并返回旧值5
3. fetch_add() 和 fetch_sub()
fetch_add()
:执行原子加法操作,并返回旧值。fetch_sub()
:执行原子减法操作,并返回旧值。
std::atomic<int> a(5);
int old_value = a.fetch_add(1); // 将a加1,并返回旧值
// a的值现在是6
4. compare_exchange_weak() 和 compare_exchange_strong()
这两个函数会比较当前原子变量的值和预期值。如果相同,就将原子变量的值设置为新值。否则,操作失败并返回 false
。
compare_exchange_weak()
:若失败,可能会重新尝试,性能相对较高。compare_exchange_strong()
:若失败,会返回false
,并且不再尝试。
std::atomic<int> a(5);
int expected = 5;
if (a.compare_exchange_weak(expected, 10)) {// 如果a的值是5,设置为10std::cout << "Value changed!" << std::endl;
} else {std::cout << "Value not changed!" << std::endl;
}
5. memory_order
std::atomic
的操作可以指定不同的内存顺序(memory ordering),控制不同线程之间的操作顺序。这对于高效并发编程非常重要。常见的内存顺序有:
memory_order_relaxed
:不保证其他线程与该线程的操作顺序。memory_order_consume
:保证后续操作依赖于当前操作。memory_order_acquire
:保证所有的读取操作不会在当前操作之前执行。memory_order_release
:保证所有的写操作不会在当前操作之后执行。memory_order_acq_rel
:同时保证 acquire 和 release。memory_order_seq_cst
:最强的内存顺序,保证所有操作的顺序一致。
应用场景
-
计数器:
原子计数器是一个典型的应用场景。多个线程可能会并发修改一个计数器,原子操作可以保证计数器值的一致性。 -
锁的实现:
一些简化版的锁(如自旋锁)可以使用原子操作来减少性能开销。 -
无锁数据结构:
通过原子操作可以设计一些高效的无锁数据结构(如无锁队列、栈等)。 -
状态标志:
原子布尔值常常用来作为状态标志,例如线程是否完成,任务是否已开始等。
好的,以下是两道练习题目,可以帮助你更好地理解和掌握 C++ 中的原子操作和多线程编程。
四、练习题目
练习题 1: 使用 std::atomic
实现线程安全计数器
题目要求
- 编写一个线程安全的计数器类,使用
std::atomic
来保证多个线程并发访问时的数据一致性。 - 设计一个类
Counter
,其中有一个原子整型成员变量value
。 - 提供
increment
(增加)和get_value
(获取当前值)两个方法。 - 创建多个线程并发地对计数器执行增加操作,最后输出计数器的最终值。
示例
#include <iostream>
#include <atomic>
#include <thread>
#include <vector>using namespace std;class Counter {
private:std::atomic<int> value;public:Counter() : value(0) {}void increment() {value.fetch_add(1, std::memory_order_relaxed);}int get_value() const {return value.load(std::memory_order_relaxed);}
};void increment_counter(Counter& counter, int times) {for (int i = 0; i < times; ++i) {counter.increment();}
}int main() {Counter counter;// 创建多个线程并发增加计数器的值vector<thread> threads;for (int i = 0; i < 5; ++i) {threads.push_back(thread(increment_counter, ref(counter), 1000));}// 等待所有线程完成for (auto& t : threads) {t.join();}cout << "Final counter value: " << counter.get_value() << endl;return 0;
}
练习题 2: 使用 compare_exchange_strong
实现自旋锁
题目要求
- 编写一个简单的自旋锁类,使用
std::atomic<bool>
来实现锁的原子操作。 - 使用
compare_exchange_strong
来实现lock
和unlock
操作。 - 在
main
函数中启动多个线程,模拟多个线程访问共享资源的场景,确保通过自旋锁控制资源的访问。
示例
#include <iostream>
#include <atomic>
#include <thread>
#include <vector>using namespace std;class SpinLock {
private:std::atomic<bool> flag;public:SpinLock() : flag(false) {}void lock() {bool expected = false;while (!flag.compare_exchange_strong(expected, true)) {expected = false; // 如果失败,重新尝试}}void unlock() {flag.store(false, std::memory_order_release);}
};SpinLock spinlock;void access_shared_resource(int thread_id) {spinlock.lock();cout << "Thread " << thread_id << " is accessing the shared resource." << endl;this_thread::sleep_for(chrono::milliseconds(100)); // 模拟处理过程cout << "Thread " << thread_id << " has finished accessing the resource." << endl;spinlock.unlock();
}int main() {vector<thread> threads;// 创建多个线程模拟并发访问共享资源for (int i = 0; i < 5; ++i) {threads.push_back(thread(access_shared_resource, i));}// 等待所有线程完成for (auto& t : threads) {t.join();}return 0;
}
总结
- 练习题 1 帮助你练习如何使用
std::atomic
实现线程安全的计数器,理解原子操作对共享数据的保护作用。 - 练习题 2 让你掌握如何使用
compare_exchange_strong
来实现自旋锁,理解锁机制的基本原理。
五、进一步讨论
为什么不使用原子操作会导致统计混乱:
假设有两个线程同时执行如下代码:
g_count = g_count + 1;
在没有原子操作的情况下,可能会发生以下步骤:
- 线程 A 读取
g_count
的值,假设为 5。 - 线程 B 也读取
g_count
的值,仍然是 5。 - 线程 A 对
g_count
进行加 1 操作,得到新的值 6。 - 线程 B 也对
g_count
进行加 1 操作,得到新的值 6。
最终的 g_count
值应该是 7(5 + 1 + 1),但实际上由于没有原子操作,线程 A 和线程 B 的加法操作是并行进行的,导致最终结果错误(g_count
被错误地更新为 6)。
解决方法: 使用原子操作,如 std::atomic
来确保这些操作是 原子的,即每次修改操作都是不可分割的,避免数据竞争。
支持的原子操作:
原子操作一般支持的操作包括:
- 基本算术操作:
++
,--
,+=
,-=
,&=
,|=
,^=
等。 - 这些操作是原子的,也就是说,当多个线程同时对
std::atomic<int>
进行增减或位操作时,编译器会确保每次操作是不可分割的。
示例
#include <iostream>
#include <atomic>
#include <thread>
using namespace std;atomic<int> g_count = 0;void mythread1() {for (int i = 0; i < 1000000; i++) {g_count++;}
}int main() {std::thread t1(mythread1);std::thread t2(mythread1);t1.join();t2.join();cout << "正常情况下结果应该是2000000次,实际是" << g_count << endl;
}
不支持的操作:
并不是所有的操作都可以直接在原子变量上执行。例如,g_count = g_count + 1;
这种方式 不行,因为它首先会读取 g_count
,然后执行加法并将结果写回 g_count
,这个过程并不是原子操作。如果多个线程同时进行这种操作,可能会导致竞态条件,结果不正确。
为什么 g_count = g_count + 1;
不行:
-
g_count = g_count + 1;
这个表达式分为两步:- 读取
g_count
的值。 - 将计算出的新值写回
g_count
。
如果在这两步之间,另一个线程也读取并修改了
g_count
的值,最终可能导致结果错误。 - 读取
-
原子操作(如
fetch_add
、fetch_sub
等)可以保证这类操作是 不可分割 的,避免中间被打断。通过原子操作,线程会依次执行加法或减法操作,确保每次修改都正确地反映到内存中。
对自己进行操作:
一些原子类型(如 std::atomic<int>
)只支持对自身进行修改的操作。这意味着,如果要执行某些复杂的表达式(例如 g_count = g_count + 1;
),需要使用更复杂的原子操作(如 fetch_add
),而不能直接使用加法或赋值操作符。
示例:
std::atomic<int> g_count(0);// 错误:不支持直接执行 g_count = g_count + 1;
g_count = g_count + 1; // 编译错误// 正确:使用原子操作
g_count.fetch_add(1, std::memory_order_relaxed); // 原子增加1
g_count++;
相关文章:
C++ atomic 原子操作
一、原子操作简介 在多线程编程中,通常我们需要多个线程共享数据。但如果不加以控制,多个线程同时访问同一数据,可能会导致数据不一致或竞争条件(race conditions)。为了解决这个问题,我们引入了 原子操作…...
Leetcode - 双周赛153
目录 一、3498. 字符串的反转度二、3499. 操作后最大活跃区段数 I三、3500. 将数组分割为子数组的最小代价四、3501. 操作后最大活跃区段数 II 一、3498. 字符串的反转度 题目连接 本题直接模拟,代码如下: class Solution {public int reverseDegree(…...
25.4 GLM-4+RAG智能标注实战:标注成本暴降60%,检索准确率飙升40%!
使用 GLM-4 优化 RAG 程序:智能标注提升检索质量 关键词:GLM-4 数据标注, RAG 优化, 检索增强生成, 向量数据库, 语义关联度分析 1. RAG 数据标注的核心挑战 在检索增强生成(Retrieval-Augmented Generation)系统中,检索数据的标注质量直接影响最终生成效果。传统标注方…...
基于sklearn实现文本摘要思考
和各位小伙伴分享一下使用sklearn进行文本摘要的思考。 第一版本 原理 提取式文本摘要的基本原理是: 将文本分割成句子 计算每个句子的重要性(权重) 选择权重最高的几个句子组成摘要 常用的句子权重计算方法: TF-IDF:基于词频-逆文档频…...
Cortex-M3 NVIC可以控制异常向量表的哪些部分
Cortex-M3 的 NVIC(嵌套向量中断控制器)不直接控制整个异常向量表,但可以管理向量表中与中断相关的部分行为。以下是 NVIC 对异常向量表的具体控制范围和相关机制: 1. NVIC 直接控制的部分 NVIC 主要管理 外部中断(IRQ) 和部分 系统异常 的行为,但对向量表本身的存储位…...
AI朝代应避免AI幻觉:分析与应对策略
随着人工智能(AI)技术的不断发展,AI的应用领域已经涵盖了文本生成、图像与视频创作以及程序编写等多个方面。然而,AI的生成能力并非没有缺陷,其中最为显著的之一就是所谓的“AI幻觉”(AI hallucination&…...
网络传输H.264方法对比
一、引言 网络传输H.264有多种方法,包括但不限于:1.通过RTP直接传输H.264;2.通过UDP传输TS流;3.通过RTP传输TS流;4.通过RTP传输PS流。本文对这些方法进行对比。 二、通过RTP直接传输H.264 这种方案就是RTP包…...
第九章:可靠通信_《凤凰架构:构建可靠的大型分布式系统》
第九章 可靠通信 一、零信任网络模型 核心难点:理解安全模型从传统边界防护到动态信任验证的转变 零信任的核心原则 不再区分"内部可信网络"与"外部不可信网络"(传统防火墙模型失效)每次请求都需要进行身份验证和授权…...
HeidiSQL:多数据库管理工具
HeidiSQL 是一款广受欢迎的免费开源数据库管理工具,专为数据库管理员及开发者设计。无论您是刚接触数据库领域的新手,还是需要同时处理多种数据库系统的专业开发者,该工具都能凭借其直观的界面和强大的功能,助您轻松完成数据管理任…...
文件系统-inode/软硬件连接(未完结)
首先我们了解一下文件简洁理解来说就是:文件内容文件属性 ---> 磁盘上存储的文件存文件的内容存文件的属性;而文件的内容----存放在每个数据块 ;文件属性存放在iNode里面。 要明白:linux系统中的文件是存储在磁盘中的…...
数据库并发控制问题
并发控制问题是数据库管理系统(DBMS)中处理多个事务并发执行时,确保数据一致性、可靠性和完整性的一系列技术和挑战。并发控制问题通常与事务的隔离性和事务之间的相互影响有关。以下是并发控制中主要的几种问题及其解决方式的详细解释&#…...
(五)智能体与工具协同——打造智能对话的超级助手
上一篇:(四)数据检索与增强生成——让对话系统更智能、更高效 在前四个阶段,我们已经搭建了一个功能强大的智能对话,并深入探讨了输入输出处理、链式工作流构建和数据检索与增强生成的细节。现在,我们将进…...
第十三届蓝桥杯 2022 省 B 刷题统计
题目描述 小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做 a a a 道题目,周六和周日每天做 b b b 道题目。请你帮小明计算,按照计划他将在第几天实现做题数大于等于 n n n 题? 输入格式 输入一行包含三个整数 a , b a, b a,b 和 n n n. 输出格…...
NLP/大模型八股专栏结构解析
1.transformer 结构相关 (1)transformer的基本结构有哪些,分别的作用是什么,代码实现。 NLP高频面试题(一)——Transformer的基本结构、作用和代码实现 (2)LSTM、GRU和Transformer结…...
不在 qtdesigner中提升,进行主题程序设计
以下是无需在Qt Designer中提升控件的完整主题化方案,保持现有代码结构的同时实现动态阴影效果管理: 一、增强主题管理器(支持动态控件发现) // thememanager.h #pragma once #include <QObject> #include <QSet> #…...
TDengine 3.3.6.0 版本中非常实用的 Cols 函数
简介 在刚刚发布的 TDengine 3.3.6.0 版本 中,新增了一个非常实用的 函数COLS ,此函数用于获取选择函数所在行列信息,主要应用在生成报表数据,每行需要出现多个选择函数结果,如统计每天最大及最小电压,并报…...
MessageQueue --- RabbitMQ WorkQueue and Prefetch
MessageQueue --- RabbitMQ WorkQueue and Prefetch 什么是WorkQueue分发机制 --- RoundRobin分发机制 --- PrefetchSpring example use prefetch --- Fair Dispatch 什么是WorkQueue Work queues,任务模型。简单来说就是让多个消费者绑定到一个队列,共同…...
第四章:透明多级分流系统_《凤凰架构:构建可靠的大型分布式系统》
第四章:透明多级分流系统 一、客户端缓存 核心目标:减少重复请求,降低服务端压力。 1. 强制缓存 定义:客户端直接根据缓存规则决定是否使用本地缓存,无需与服务端交互。关键HTTP头: Cache-Control&#…...
题解:AT_abc241_f [ABC241F] Skate
一道经典的 bfs 题。 提醒:本题解是为小白专做的,不想看的大佬请离开。 这道题首先一看就知道是 bfs,但是数据点不让我们过: 1 ≤ H , W ≤ 1 0 9 1\le H,W\le10^9 1≤H,W≤109。 那么我们就需要优化了,从哪儿下手…...
热题100-字母异位词分组
方法用Arrays.sort对每个String 进行排序,毕竟排序以后都一样了,然后放入Map中的key跟value,可以一对多,然后返回的时候只要返回Map中所有的values就可以了 class Solution {public List<List<String>> groupAnagram…...
WiFi加密协议
目录 1. 认证(Authentication) 1.1 开放系统认证(Open System Authentication) 1.2 共享密钥认证(Shared Key Authentication) 1.3 802.1X/EAP认证(企业级认证) 2. 关联(Association) 3. 加密协议(Security Handshake) 整体流程总结…...
【AI提示词】书籍推荐专家
提示说明 帮助您找到适合您的好书。 提示词 ## Role: 书籍推荐专家## Profile: - author: xxx - version: 1.0.0 - language: 中文 - description: 我是一位书籍推荐专家,我可以帮助您找到适合您的好书。## Goals: - 吸引读者的注意力,引导他们阅读更…...
Linux进程间通信——有名管道
一.概念 函数形式:int mkfifo(const char \*filename,mode_t mode); 功能:创建管道文件 参数:管道文件文件名\路径,权限,创建的文件权限仍然和umask有关系。 返回值:创建成功返回0,创建失败返回…...
JavaScript基础--01-JS简介
字面量:数字、字符串、布尔值 前言JavaScript背景Web前端有三层:发展历史JavaScript的发展:蒸蒸日上 JavaScript介绍JavaScript入门易学性JavaScript是脚本语言JavaScript的组成 JavaScript 的特点特点1:解释型语言特点2ÿ…...
2025年 能够有效提升AI的生成质量和逻辑严谨性 的通用型系统提示
以下是三个经过精心设计的通用型系统提示(System Prompt),能够有效提升AI的生成质量和逻辑严谨性,适用于各类对话、分析和创作场景: Prompt 1 - 专家级分步验证模式 你是一个具备跨领域知识整合能力的超级AIÿ…...
xss攻击
XSS 攻击,即跨站脚本攻击(Cross - Site Scripting),是一种常见的 Web 应用程序安全漏洞。以下是关于它的详细介绍: 原理 输入输出控制不严:程序对用户输入和输出处理不当。用户输入的数据没有经过充分的过…...
Node.js核心模块及Api详解
以下是 Node.js 最常用的核心模块及 API 详解,按使用频率和重要性分类整理: 一、高频核心模块 1. fs 文件系统 const fs require(fs); const fsPromises require(fs).promises; // Promise 版本// 异步读取文件(推荐) fs.read…...
解析keras.layers.Layer中的权重参数
文章目录 概要__init__()build()add_weight() 概要 keras.layers.Layers是所有层对象的父类,在keras.layers下所有实现类都是其子类,自定义层时需要继承该类。 init() Layer的构造函数,需要注意两个参数trainable和name trainable:指定该层…...
原型设计工具即时设计的简单使用攻略
即时设计是一款国产在线协同设计工具,支持从原型设计到开发交付的全流程,尤其擅长Web/App界面原型制作。其核心优势体现在: • 零门槛入门:浏览器直接访问无需安装,中文界面友好 • 资源生态完善:内置3000原…...
深入解析C++智能指针:从内存管理到现代编程实践
一、智能指针核心概念 1.1 智能指针的本质 智能指针是基于**RAII(资源获取即初始化)**的封装类,通过对象生命周期自动管理动态内存。与传统指针相比: 特性原始指针智能指针内存管理手动自动空指针检查需显式判断支持空状态检测…...
在 Langflow 中构建灵活的自定义组件:从基础到高级实践
本文深入探讨了如何在 Langflow 平台中创建功能丰富的自定义组件。通过详细的目录结构解析、分步实现指南和多个实战案例,帮助开发者掌握利用 Python 生态扩展低代码平台的方法,打造高效的数据处理流程。 理解组件架构设计 自定义组件是在 Langflow 中创…...
【数学建模】(时间序列模型)ARIMA时间序列模型
ARIMA时间序列模型详解及常见时间序列模型概览 文章目录 ARIMA时间序列模型详解及常见时间序列模型概览1 引言2 ARIMA模型的基本概念3 ARIMA模型的组成部分详解3.1 AR模型 (自回归模型)3.2 MA模型 (移动平均模型)3 I (差分) 4 ARIMA模型的建模步骤5 Python实现ARIMA模型6 常见时…...
模版的特性及其编译分离
1.模版的分类 模版参数分为 类型形参 和 非类型形参 类型形参:出现在模版参数列表中,跟在class和typename之后的参数类型名称 非类型形参:就是用一个常量作为类(函数)模版的一个参数,在类(函…...
8电池_多绕组反激式变压器均衡_4模式
(1)8节串联锂离子电池组 (2)多绕组双向反激式变压器,1个变压器解决多电池均衡 (3)亮点:支持1建切换4种均衡算法–>全网唯一 (4)多绕组变压器均衡也能设计多种均衡算法–>全网唯一 锂离子电池均衡,均衡拓扑,均衡算法...
6.1 python加载win32或者C#的dll的方法
python很方便的可以加载win32的方法以及C#编写的dll中的方法或者变量,大致过程如下。 一.python加载win32的方法,使用win32api 1.安装库win32api pip install win32api 2.加载所需的win32函数并且调用 import win32api win32api.MessageBox(0,"…...
STP学习
{所有内容均来自于西安欧鹏的陈俊老师} STP生成树 当二层交换机意外成环路的时候会发生: 1.广播风暴:当广播帧进入环路时,会被不断复制并传输,导致网络中的广播流量急剧增加,消耗大量的网络带宽,降低网络…...
特征值与特征向量:从理论到应用的全面解析
特征值与特征向量:从理论到应用的全面解析 一、特征值与特征向量核心概念 定义 对于方阵 ( A ),若存在标量 ( \lambda ) 和非零向量 ( v ),使得: [ A v \lambda v ] 则 ( \lambda ) 为特征值,( v ) 为对应的特征向…...
【Python】数组的条件逻辑统计运算元素排序
【Python】数组的条件逻辑&统计运算&元素排序: 一.条件逻辑二.统计运算三.数组元素排序检索数组元素是否满足条件查找数组的唯一元素判断元素是否在其他数组中 一.条件逻辑 import numpy as np arr_x np.array([1, 5, 7]) arr_y np.array([2, 6, 8]) arr_…...
数据流和重定向
1、数据流 不管正确或错误的数据都是默认输出到屏幕上,所以屏幕是混乱的。所以就需要用数据流重定向将这两 条数据分开。数据流重定向可以将标准输出和标准错误输出分别传送到其他的文件或设备去 标准输入(standard input,简称stdinÿ…...
Jetpack Compose 自定义组件完全指南
Jetpack Compose 自定义组件完全指南 Compose 的声明式 UI 范式为创建自定义组件提供了前所未有的灵活性。本指南将带你从基础到高级全面掌握 Compose 自定义组件的开发技巧。 一、自定义组件基础 1.1 基本结构 一个最简单的自定义组件: Composable fun Greeti…...
ETF 场内基金是什么?佣金最低又是多少呢?
嘿,朋友们,大家好啊,我是StockMasterX,今天咱们就坐下来慢慢聊聊这个话题,ETF 场内基金到底是个啥东西,它的佣金最低能到多少,真的是个值得深挖的问题。 说起ETF,我还记得刚入行那会…...
【C++篇】类与对象(中篇) 解密C++类的核心:六大默认成员函数详解与避坑指南
文章目录 前言一、类的六个默认成员函数二、构造函数1. 概念2. 特性(牢记) 三、析构函数1. 概念2. 特性(牢记) 四、拷贝构造函数1. 概念2. 特性(牢记) 五、赋值运算符重载1. 运算符重载2. 赋值运算符重载前…...
001 vue
https://cn.vuejs.org/ 文章目录 v-bindv-modelv-on修饰符条件渲染/控制:v-if v-show列表渲染 M:即Model,模型,包括数据和一些基本操作 V:即View,视图,页面渲染结果 VM:即View-Mode…...
web forms可视化开发显示的网页是用ExpressionWebEditorFrame控件,是IE内核还是简单的HTML解析?如何让他加载CSS和JS?
web forms可视化开发显示的网页是用ExpressionWebEditorFrame控件,是IE内核还是简单的HTML解析?如何让他加载CSS和JS? 1. ExpressionWebEditorFrame 控件的内核及解析机制 在 Visual Studio 中用于 Web Forms 可视化开发的 ExpressionWebEditorFrame 控件主要基于 Internet…...
$R^n$超平面约束下的向量列
原向量: x → \overset{\rightarrow}{x} x→ 与 x → \overset{\rightarrow}{x} x→法向相同的法向量(与 x → \overset{\rightarrow}{x} x→同向) ( x → ⋅ n → ∣ n → ∣ 2 ) n → (\frac{\overset{\rightarrow}x\cdot\overset{\righta…...
英伟达新一代GPU架构(50系列显卡)PyTorch兼容性解决方案
随着NVIDIA不断推出基于新架构的GPU产品,机器学习框架需要相应地更新以支持这些硬件。本文记录了在RTX 5070 Ti上运行PyTorch时遇到的CUDA兼容性问题,并详细分析了问题根源及其解决方案,以期为遇到类似情况的开发者提供参考。 在Anaconda虚…...
16.2Linux自带的LED灯驱动实验(详细编写)_csdn
这个实验不用自己编写代码。 1、在linux源代码中,打开 stm32mp15-pinctrl.dtsi 文件并进行修改: make uImage LOADADDR0XC2000040 -j8 //编译内核然后: 2、修改设备节点,打开 stm32mp157d-atk.dts: 其中࿱…...
Java 大视界 -- Java 大数据在智慧交通停车场智能管理与车位预测中的应用实践(174)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...
HashMap 底层原理详解
1. 核心数据结构 JDK 1.7 及之前:数组 链表 JDK 1.8 及之后:数组 链表/红黑树(链表长度 ≥8 时转红黑树,≤6 时退化为链表) // JDK 1.8 的 Node 定义(链表节点) static class Node<K,V&g…...
重生之我是去噪高手——diffusion model
diffusion model是如何运作的? 想象一下,你有一张清晰的图片。扩散模型的核心思想分为两个过程: 前向过程(Forward Process / Diffusion Process):逐步加噪反向过程(Reverse Process / Denois…...