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所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ 2023_02_1502/20
- ♥ 2022_03_1403/17
- ♥ 2022_09_1409/26
- ♥ 2020_04_2905/01
- ♥ 2020_04_2804/28
- ♥ 2023_02_0902/11
热评文章
- 2022_09_14 0
- 2020_11_19_01 0
- 2022_02_18 0
- 2023_02_05 0
- 2020_11_09 0
- 2022_02_24_01 0