Windows
Mutex
- 创建或打开
Mutex
1 2 3 4 5 6 7 8 9 |
HANDLE hMutex = CreateMutex( NULL, // 默认安全属性 FALSE, // 初始所有者:FALSE表示创建时不被任何线程持有 L"Global\\MyMutex" // 命名Mutex(跨进程需前缀"Global\\"或"Local\\") ); if (hMutex == NULL) { DWORD error = GetLastError(); // 处理错误 } |
- 等待获取
Mutex
所有权- 通过
WaitForSingleObject
阻塞当前线程,直到Mutex
变为有信号(可获取)状态:
- 通过
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
DWORD dwWaitResult = WaitForSingleObject(hMutex, INFINITE); // 无限等待 switch (dwWaitResult) { case WAIT_OBJECT_0: // 成功获取Mutex // 执行临界区操作 break; case WAIT_ABANDONED: // Mutex被其他线程异常终止(需处理数据一致性) // 修复可能受损的共享资源 break; case WAIT_TIMEOUT: // 仅在设置超时时间时可能返回 // 处理超时逻辑 break; case WAIT_FAILED: // 系统错误 // 检查GetLastError() break; } |
- 释放
Mutex
1 2 3 4 |
if (!ReleaseMutex(hMutex)) { DWORD error = GetLastError(); // 处理释放失败(如非所有者线程尝试释放) } |
- 关闭句柄
- 使用
CloseHandle
关闭Mutex
句柄(系统在进程退出时自动关闭,但显式关闭更安全):
- 使用
1 |
CloseHandle(hMutex); |
C++
std::mutex
内部实现
- 源码
1 2 3 4 5 6 7 |
_EXPORT_STD class mutex : public _Mutex_base { // class for mutual exclusion public: mutex() noexcept = default; mutex(const mutex&) = delete; mutex& operator=(const mutex&) = delete; }; |
- 基类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
class _Mutex_base { // base class for all mutex types public: #ifdef _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR _Mutex_base(int _Flags = 0) noexcept { _Mtx_init_in_situ(_Mymtx(), _Flags | _Mtx_try); } #else // ^^^ defined(_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR) / !defined(_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR) vvv constexpr _Mutex_base(int _Flags = 0) noexcept { _Mtx_storage._Critical_section = {}; _Mtx_storage._Thread_id = -1; _Mtx_storage._Type = _Flags | _Mtx_try; _Mtx_storage._Count = 0; } #endif // ^^^ !defined(_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR) ^^^ _Mutex_base(const _Mutex_base&) = delete; _Mutex_base& operator=(const _Mutex_base&) = delete; void lock() { //...} void unlock() noexcept /* strengthened */ { //...} protected: _NODISCARD_TRY_CHANGE_STATE bool _Verify_ownership_levels() noexcept { if (_Mtx_storage._Count == INT_MAX) { // only occurs for recursive mutexes (N4950 [thread.mutex.recursive]/3) --_Mtx_storage._Count; return false; } return true; } private: friend condition_variable; friend condition_variable_any; _Mtx_internal_imp_t _Mtx_storage{}; _Mtx_t _Mymtx() noexcept { return &_Mtx_storage; } }; |
- 再看这个
_Mtx_internal_imp_t
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
struct _Mtx_internal_imp_t { #if defined(_CRT_WINDOWS) || defined(UNDOCKED_WINDOWS_UCRT) // for Windows-internal code static constexpr size_t _Critical_section_size = 2 * sizeof(void*); #elif defined(_WIN64) // ordinary 64-bit code static constexpr size_t _Critical_section_size = 64; #else // vvv ordinary 32-bit code vvv static constexpr size_t _Critical_section_size = 36; #endif // ^^^ ordinary 32-bit code ^^^ int _Type{}; union { _Stl_critical_section _Critical_section{}; _STD _Aligned_storage_t<_Critical_section_size, alignof(void*)> _Cs_storage; }; long _Thread_id{}; int _Count{}; }; |
- 再看
_Stl_critical_section
1 2 3 4 5 6 |
using _Smtx_t = void*; struct _Stl_critical_section { void* _Unused = nullptr; // TRANSITION, ABI: was the vptr _Smtx_t _M_srw_lock = nullptr; }; |
std::mutex
实现解析
- 基类的核心成员
_Mtx_storage
(类型为_Mtx_internal_imp_t
)包含以下字段:_Critical_section
:通过_Stl_critical_section
实现,实际指向SRW
(Slim Reader/Writer
)锁_Thread_id
:记录当前持有锁的线程ID
_Count
:递归锁计数(仅在递归互斥量中使用)_Type
:锁类型标识(例如是否支持递归)
_Stl_critical_section
的实质- 该结构体中的
_M_srw_lock
字段(类型为_Smtx_t
,即void*
)在Windows
平台下指向的是SRW
锁对象 SRW
锁是Windows
提供的用户态轻量级锁,无需通过内核对象实现
- 该结构体中的
STL
顺序容器
array
- 固定大小数组,内存连续,编译时确定容量
- 替代原生数组的封装版,支持STL算法
vector
- 动态数组,内存连续,支持快速随机访问(
O(1)
) - 尾部插入/删除高效,中间插入需移动元素(
O(n)
)
- 动态数组,内存连续,支持快速随机访问(
list
- 双向链表,内存非连续,任意位置插入/删除高效(
O(1)
) - 不支持随机访问,遍历效率低
- 双向链表,内存非连续,任意位置插入/删除高效(
forward_list
- 单向链表,仅支持前向迭代
deque
- 双端队列,分段连续内存,支持两端高效插入/删除(
O(1)
) - 随机访问效率接近
vector
,但内存消耗略高
- 双端队列,分段连续内存,支持两端高效插入/删除(
关联容器
-
基于红黑树实现,元素按键值自动排序,提供对数时间复杂度的查找(
O(log n)
) -
set
- 唯一键值集合,自动去重
-
map
- 键值对集合,键唯一
-
multiset
- 允许键重复的变体
-
multimap
- 允许键重复的变体
无序关联容器
- 基于哈希表实现(
C++11
引入),元素无序存储,平均常数时间复杂度(O(1))
: unordered_set
/unordered_map
- 哈希表实现的集合和键值对
unordered_multiset
/unordered_multimap
- 允许键重复的变体
容器适配器
- 基于其他容器封装,提供特定接口:
stack
- 后进先出(
LIFO
),默认基于deque
实现
- 后进先出(
queue
- 先进先出(
FIFO
),默认基于deque
实现
- 先进先出(
priority_queue
- 优先队列,默认基于
vector
+堆算法实现
- 优先队列,默认基于
Windbg
dds
- 用于显示指定内存范围内的数据,并尝试将每个双字(
4
字节)解析为符号(如函数名、变量名等),从而辅助调试人员快速理解内存内容的语义
1 |
dds 0x0012ff40 L10 // 显示从0x0012ff40开始的16个双字 |
对比其他
dd
- 仅显示双字数值,无符号解析
dps
- 按指针大小(
32
位系统为4
字节,64
位为8
字节)解析符号,适用于指针数组
- 按指针大小(
dqs
- 按
8
字节(四字)解析符号,常用于64
位环境
- 按
dds
- 独特之处在于固定按
4
字节解析符号,适合分析32位代码或结构体中的双字字段(如函数表、虚表)
- 独特之处在于固定按
寄存器
C++11
C++20特性
模块(Modules
)
- 功能:替代传统头文件,解决编译速度慢和命名污染问题
- 模块通过
.cppm
文件定义接口,提供更清晰的代码组织方式
- 模块通过
- 优势:减少编译时间,增强封装性,避免重复包含问题
1 2 3 4 5 6 7 8 9 10 |
// math.cppm export module math; export int add(int a, int b) { return a + b; } // main.cpp import math; int main() { int result = add(3, 4); // 结果 7 return 0; } |
协程(Coroutines
)
- 功能:支持函数暂停与恢复,简化异步编程和生成器模式
- 使用
co_await
、co_yield
和co_return
关键字
- 使用
- 应用场景:异步
I/O
、事件驱动编程
1 2 3 4 5 6 7 8 9 |
#include <coroutine> struct Task { struct promise_type { /* 协程控制逻辑 */ }; std::coroutine_handle<promise_type> handle; }; Task async_task() { co_await std::suspend_always{}; // 暂停 co_return; // 恢复后返回 } |
范围库(Ranges
)
- 功能:提供链式操作和惰性求值,简化集合处理
- 优势:支持管道操作符(
),无需中间容器
1 2 3 4 |
#include <ranges> std::vector<int> nums = {1,2,3,4,5}; auto even = nums | std::views::filter([](int n) { return n % 2 == 0; }); // 输出:2 4 |
概念(Concepts
)
- 功能:约束模板参数,提升代码可读性和错误提示
- 应用:限制模板类型,避免隐式错误
1 2 |
template<typename T> concept Integral = std::is_integral_v<T>; template<Integral T> T add(T a, T b) { return a + b; } |
三路比较运算符
- 功能:简化比较操作,自动生成
<
、>
、==
等运算符 - 返回值:
std::strong_ordering
类型,明确比较结果
1 2 3 |
struct Point { int x, y; auto operator<=>(const Point&) const = default; }; Point a{1,2}, b{1,3}; if (a < b) { /* 成立 */ } |
格式化库(std::format
)
- 功能:类型安全的字符串格式化,类似
Python
的str.format
- 优势:替代
printf
和iostream
,避免类型错误
1 2 |
#include <format> std::string msg = std::format("Hello, {}!", "World"); // "Hello, World!" |
std::span
- 提供连续内存的轻量级视图,如数组或容器片段,无需拷贝数据
- 示例:原生数组
1 2 3 4 5 6 7 8 9 10 11 |
#include <span> #include <iostream> int main() { int arr[] = {1, 2, 3, 4, 5}; std::span<int> arrSpan(arr); // 自动推断数组大小 for (int num : arrSpan) { std::cout << num << " "; // 输出:1 2 3 4 5 } return 0; } |
vector
1 2 3 4 5 6 7 8 9 |
#include <span> #include <vector> int main() { std::vector<int> vec = {6, 7, 8, 9, 10}; std::span<int> vecSpan(vec); // 引用整个向量 vecSpan[0] = 100; // 修改会同步到原向量 return 0; } |
std::array
1 2 3 4 5 6 7 8 9 |
#include <span> #include <array> int main() { std::array<int, 5> arrObj = {11, 12, 13, 14, 15}; std::span<int> arraySpan(arrObj); std::cout << arraySpan.size(); // 输出:5 return 0; } |
- 子范围操作(切片)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
auto first3 = arrSpan.first(3); // 前3个元素 for (int num : first3) { std::cout << num << " "; // 输出:1 2 3 } auto last2 = arrSpan.last(2); // 后2个元素 for (int num : last2) { std::cout << num << " "; // 输出:4 5 } // 自定义切片 auto subSpan = arrSpan.subspan(1, 3); // 从索引1开始,取3个元素 for (int num : subSpan) { std::cout << num << " "; // 输出:2 3 4 } |
- 作为函数参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <span> #include <vector> // 统一接收数组、向量等连续内存数据 void printData(std::span<const int> data) { for (int num : data) { std::cout << num << " "; } } int main() { int arr[] = {1, 2, 3}; std::vector<int> vec = {4, 5, 6}; printData(arr); // 输出:1 2 3 printData(vec); // 输出:4 5 6 return 0; } |
- 动态修改底层数据
1 2 3 4 5 6 7 8 9 10 |
#include <span> #include <vector> int main() { std::vector<int> vec = {0, 1, 2, 3}; std::span<int> mutableSpan(vec); mutableSpan[0] = 100; // 修改原向量数据 std::cout << vec[0]; // 输出:100 return 0; } |
- 边界安全访问
1 2 3 |
std::cout << arrSpan.front(); // 输出第一个元素:1 std::cout << arrSpan.back(); // 输出最后一个元素:5 // arrSpan[5] 会触发运行时错误(越界) |
std::jthread
- 自动管理线程生命周期,支持停止令牌(
stop_token
),避免资源泄漏
constexpr
增强
- 支持动态内存分配、虚函数和异常处理,如:
1 |
constexpr int* arr = new int[3]{1,2,3}; // 编译时分配内存 |
Lambda
改进
- 支持模板参数:
auto lambda = []<typename T>(T x) { ... };
- 初始化捕获:
[value = std::move(obj)]{};
char8_t
类型
- 明确表示
UTF-8
字符,增强编码安全性char8_t
是与char
、char16_t
、char32_t
完全不同的独立类型,但其底层表示与unsigned char
一致(至少8
位,可能更大)
- 区分普通字符(依赖本地编码)与
UTF-8
字符,避免编码混淆
1 2 |
const char8_t* utf8_str = u8"你好"; // C++20 合法 const char* legacy_str = u8"Hello"; // C++20 编译错误(需用 char8_t*)[1,3](@ref) |
C++23特性
错误处理的现代化:std::expected
C++23
通过std::expected<T, E>
类型提供了更优雅的错误处理方案,替代传统的错误码或异常机制- 功能:封装可能成功或失败的操作结果,成功时返回类型
T
的值,失败时携带类型E
的错误信息 - 优势:类型安全、代码可读性强、性能优于异常机制
1 2 3 4 5 |
#include <expected> std::expected<int, std::string> divide(int a, int b) { if (b == 0) return std::unexpected("Division by zero"); return a / b; } |
多维数据处理:std::mdspan
- 作为
std::span
的多维扩展,std::mdspan
支持非拥有的多维数组视图,适用于科学计算和图像处理等场景 - 功能:动态表示多维数据(如矩阵),支持任意维度
1 2 3 4 |
#include <mdspan> std::vector<int> data = {1,2,3,4,5,6}; std::mdspan<int, std::extents<2,3>> matrix(data.data()); // 2x3矩阵 std::cout << matrix(1,2); // 输出第2行第3列的元素(值6) |
显式 this
参数(Deducing This
)
- 引入显式
this
参数语法,统一成员函数的左值和右值版本,简化模板代码 - 功能:通过
this
参数显式声明对象实例,增强代码清晰度
1 2 3 4 5 6 7 |
class Cat { public: void meow(this Cat& self) { // 显式this参数 std::cout << self.name << "喵~"; } std::string name; }; |
编译时计算的增强
constexpr
支持try-catch
- 允许在编译时处理异常,扩展了常量表达式的应用场景:
1 2 3 4 |
constexpr int safe_divide(int a, int b) { try { return a / b; } catch (...) { return 0; } } |
if consteval
指令- 检测当前上下文是否为编译时求值,优化代码路径:
1 2 3 4 |
constexpr int square(int x) { if consteval { return x * x; } // 编译时执行 else { return x * x; } // 运行时执行 } |
格式化输出的简化
- 新增
std::print
和std::println
,提供类型安全的格式化输出,取代繁琐的printf
或iostream
- 支持
{}
占位符,自动推导类型
1 2 |
#include <print> std::println("Name: {}, Age: {}", "Alice", 25); // 自动换行 |
范围库(Ranges
)增强
C++23
扩展了std::ranges
的功能,新增算法和视图(如zip
、chunk_by
),支持更简洁的集合操作:
1 2 |
std::vector<int> nums = {1,2,3,4,5}; auto squared = nums | std::views::transform([](int n) { return n*n; }); |
协程优化
- 增强协程的灵活性和性能,支持更高效的异步编程
std::generator
- 简化惰性序列生成器的实现:
1 2 3 4 |
#include <generator> std::generator<int> range(int start, int end) { for (int i=start; i<end; ++i) co_yield i; } |
std::byteswap
- 快速反转字节顺序,适用于网络通信和数据序列化:
1 2 |
uint16_t value = 0x1234; uint16_t swapped = std::byteswap(value); // 0x3412 |
std::to_underlying
- 将枚举转换为底层类型:
1 2 |
enum class Color : uint8_t { Red=1 }; std::cout << std::to_underlying(Color::Red); // 输出1 |
JavaScript
概述
JavaScript
的主线程是单线程的,即同一时间只能执行一个任务- 这种设计最初是为了避免多线程操作
DOM
导致的同步问题(如同时修改和删除元素时无法确定执行顺序)
- 这种设计最初是为了避免多线程操作
同步与异步分工
- 同步代码:
- 直接在主线程的调用栈中执行(如变量声明、循环、函数调用)
- 异步代码:
- 通过事件循环(
Event Loop
) 调度,委托给浏览器/Node.js
的其他线程处理(如定时器、网络请求),完成后回调加入任务队列等待主线程空闲时执行
- 通过事件循环(
事件循环的运行流程
- 主线程执行同步任务,遇到异步任务时注册回调到
Web API
(如setTimeout
由定时器线程处理) - 异步任务完成后,回调被分类到宏任务队列(如
setTimeout
)或微任务队列(如Promise.then
) - 主线程清空同步任务后,优先执行所有微任务,再执行一个宏任务,循环往复
多线程协作
Web Worker
的多线程支持- 后台线程:可通过
new Worker()
创建独立线程处理CPU
密集型任务(如大数据计算),但无法直接操作DOM
,需通过消息传递与主线程通信 - 线程隔离性:
Worker
线程与主线程不共享内存,避免数据竞争问题
- 后台线程:可通过
- 浏览器多线程协作
- 渲染线程、网络线程等:虽然
JavaScript
主线程是单线程,但浏览器会启动其他线程辅助渲染、网络请求等(如CSS
解析、图片加载),最终通过事件循环与主线程交互
- 渲染线程、网络线程等:虽然
实践中的解决方案
- 异步编程范式
Promise/async-await
:替代回调地狱,提升代码可读性- 任务分片:将大任务拆解为多个微任务,通过
requestIdleCallback
调度执行
- 示例:基础
Promise
示例- 模拟一个异步获取用户数据的
Promise
,包含成功和失败场景:
- 模拟一个异步获取用户数据的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// 创建 Promise function getUserData(userId) { return new Promise((resolve, reject) => { setTimeout(() => { if (userId === 1001) { resolve({ id: 1001, name: "Alice", role: "admin" }); // 成功 } else { reject(new Error("User not found")); // 失败 } }, 1000); // 模拟 1 秒延迟 }); } // 调用 Promise getUserData(1001) .then(data => console.log("用户数据:", data)) .catch(error => console.error("错误:", error.message)); // 输出结果: // 用户数据: { id: 1001, name: "Alice", role: "admin" } |
- 示例:
async/await
改造- 将上述
Promise
用async/await
重构,并添加错误处理:
- 将上述
1 2 3 4 5 6 7 8 9 10 11 12 13 |
async function fetchUser() { try { const user = await getUserData(1001); // 等待 Promise 解决 console.log("用户数据:", user); return user; } catch (error) { console.error("错误:", error.message); throw error; // 重新抛出错误供外部处理 } } // 调用 async 函数 fetchUser().then(() => console.log("操作完成")); |
- 示例:并行异步操作
- 使用
Promise.all
和async/await
处理多个并发请求
- 使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// 模拟多个异步任务 const fetchProfile = (userId) => Promise.resolve({ userId, profile: "..." }); const fetchOrders = (userId) => Promise.resolve({ userId, orders: [...] }); async function loadUserDashboard(userId) { try { // 并行发起请求 const [profile, orders] = await Promise.all([ fetchProfile(userId), fetchOrders(userId) ]); console.log("整合数据:", { profile, orders }); } catch (error) { console.error("加载失败:", error); } } loadUserDashboard(1001); |
- 示例:链式异步操作
- 展示
async/await
如何替代Promise
链式调用
- 展示
1 2 3 4 5 6 7 8 9 10 |
async function processOrder(orderId) { try { const order = await fetchOrder(orderId); // 获取订单 const payment = await validatePayment(order); // 验证支付 await sendConfirmation(order.userId); // 发送确认 console.log("订单处理完成"); } catch (error) { console.error("流程中断:", error); } } |
- 性能优化策略
Web Worker
分流计算:将耗时任务(如视频解码)迁移到后台线程- 虚拟化渲染:对长列表使用虚拟滚动技术,减少
DOM
操作压力
本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ 2022_02_24_0203/01
- ♥ 2022_02_24_0103/01
- ♥ 2020_11_0511/23
- ♥ 2022_03_0103/01
- ♥ 2025_03_1103/11
- ♥ 2023_02_2002/20