Item40:对于并发使用atomic,对于特殊内存使用volatile
为什么要区分这两个关键字?volatile 之所以被拿来和并发编程混为一谈,是因为: 其他语言(Java/C#)中 volatile 有并发语义; 部分 C++ 编译器给 volatile 加了非标准的并发特性; 但在标准 C++ 中,volatile 和并发毫无关系,而开发者常把它和处理并发的 std::atomic 搞混,这是文章要解决的核心问题。 std::atomic:专为并发设计的原子操作工具 能力:保证对变量的操作(读、写、读 - 改 - 写)是原子性的(不可分割),无需互斥锁,底层通过专用机器指令实现,比锁更高效。 比如 ++ai(ai 是 std::atomic<int>)是完整的原子操作,多线程执行时不会出现 “读 - 改 - 写” 拆分导致的错误; 对比普通变量 /volatile 变量的自增:会拆分成 “读值→加 1→写回” 三步,多线程下会出现计数错误(比如两次自增只得到 1 而非 2)。 内存序限制:默认的 “顺序一致性” 模型会限制编译器 / 硬件的指令重排,保证操作的执行顺序和代码逻辑一致。...
Item38:关注不同线程句柄的析构行为
线程句柄的析构逻辑差异std::thread 和 std::future 均可视作系统线程的句柄,但析构行为存在本质差异:可结合的 std::thread 析构会直接终止程序,而 std::future 析构永不终止程序,其行为完全由关联的 “共享状态” 决定。 共享状态(shared state)的作用异步任务的结果既不存储在调用者的 future 中,也不存储在被调用者的 std::promise 中(两者生命周期均不满足需求),而是存储在独立的堆上对象 —— 共享状态中;该状态由引用计数管理生命周期,future 的析构行为完全依赖其关联的共享状态类型。 future 析构的两种行为1. 正常行为(绝大多数场景)直接销毁 future 自身的数据成员,仅递减共享状态的引用计数,既不隐式 join 也不隐式 detach。 典型场景:由 std::packaged_task 创建的 future(非 std::async 关联的共享状态),析构均遵循此逻辑;此时线程管理(join/detach)需开发者手动处理对应的 std::thread。 2. 特殊例外行为(仅满足 3 ...
滕王阁序
引言《滕王阁序》是初唐诗人王勃的千古名篇,作于上元二年(675年)洪州滕王阁宴会上。文章辞藻华丽、意境壮阔,融写景、抒情、议论于一体,被誉为“千古第一骈文”。 原文正文 豫章故郡,洪都新府。星分翼轸,地接衡庐。襟三江而带五湖,控蛮荆而引瓯越。物华天宝,龙光射牛斗之墟;人杰地灵,徐孺下陈蕃之榻。雄州雾列,俊采星驰,台隍枕夷夏之交,宾主尽东南之美。都督阎公之雅望,棨戟遥临;宇文新州之懿范,襜帷暂驻。十旬休假,胜友如云;千里逢迎,高朋满座。腾蛟起凤,孟学士之词宗;紫电清霜,王将军之武库。家君作宰,路出名区;童子何知,躬逢胜饯。 时维九月,序属三秋。潦水尽而寒潭清,烟光凝而暮山紫。俨骖騑于上路,访风景于崇阿。临帝子之长洲,得天人之旧馆。层峦耸翠,上出重霄;飞阁流丹,下临无地。鹤汀凫渚,穷岛屿之萦回;桂殿兰宫,即冈峦之体势。 披绣闼,俯雕甍。山原旷其盈视,川泽纡其骇瞩。闾阎扑地,钟鸣鼎食之家;舸舰弥津,青雀黄龙之舳。云销雨霁,彩彻区明。落霞与孤鹜齐飞,秋水共长天一色。渔舟唱晚,响穷彭蠡之滨;雁阵惊寒,声断衡...
基础与语法与数据结构:数据类型与变量
核心要点速览 数据类型分类:基本类型、复合(派生)类型、自定义类型 核心复合类型:指针、引用、数组、结构体、联合体、枚举 变量关键特性:存储类别(auto/static/extern 等)、初始化要求、作用域与生命周期 常量核心:const(只读)、constexpr(编译期常量) 类型转换:隐式转换(编译器自动)、显式转换(四种强制转换) 一、数据类型1.1 基本类型基本类型是 C++ 内置的基础数据类型,具有固定内存大小(部分受平台影响)和明确取值范围。 类型 典型大小(32/64 位系统) 含义 / 范围 面试考点 bool 1 字节 布尔值:true(1)/false(0) sizeof(bool)恒为 1;不可用 0 / 非 0 代替(语法允许但不规范) char 1 字节 ASCII 码:-128127 或 0255 区分signed char(带符号)和unsigned char(无符号);默认符号性由编译器决定 short 2 字节 短整数:-32768~32767 与short ...
基础与语法与数据结构:程序结构与预处理
核心要点速览 流程:预处理→编译→汇编→链接→执行 程序入口:main 函数(返回值 int,return 0 表示正常退出) 核心预处理指令:#include(头文件包含)、#define(宏定义)、条件编译(#ifdef/#ifndef/endif)、#pragma once(头文件防重复包含) 核心要点速览 流程:预处理→编译→汇编→链接→执行 程序入口:main 函数(返回值 int,return 0 表示正常退出) 核心预处理指令:#include(头文件包含)、#define(宏定义)、条件编译(#ifdef/#ifndef/endif)、#pragma once(头文件防重复包含) 一、程序结构 执行流程:预处理→编译→汇编→链接→执行 预处理是编译的第一个阶段,由预处理器处理所有以 #开头的指令,生成 “预处理后的源代码” 预处理核心操作:消除注释、展开宏、处理条件编译、引入头文件内容 阶段 核心操作 产出物 关键工具 预处理 处理 # 指令、展开宏、引入头文件 预处理后的源代码 预处理器(cpp) ...
并发编程:线程同步
核心要点速览 数据竞争:多线程并发读写共享资源(至少一个写操作)的未定义行为 互斥锁:std::mutex(基础)、lock_guard(RAII 推荐)、unique_lock(灵活,配条件变量) 条件变量:wait()(阻塞 + 释锁)、notify_one()/notify_all(),需配互斥锁 + 谓词(解虚假唤醒) 原子操作:std::atomic(硬件级原子性,无锁),核心内存序(relaxed/acquire/release/seq_cst) 读写锁:std::shared_mutex(读共享、写独占),优化读多写少场景 常见问题:死锁(固定加锁顺序避免)、虚假唤醒(谓词检查解决)、活锁 / 饥饿(延迟 / 公平锁缓解) 一、线程同步的目标 保证数据一致性:避免多线程读写共享资源导致的结果不可预测。 控制执行顺序:确保线程按业务逻辑要求的顺序执行(如生产者先生产,消费者后消费)。 二、核心同步机制1. 互斥锁:独占式临界区访问 核心原理:通过 “加锁 - 操作 - 解锁”,保证同一时间仅一个线程进...
网络编程:IO模型与高并发
核心要点速览 五大 IO 模型:阻塞 IO(低并发)、非阻塞 IO(忙等)、IO 多路复用(高并发核心)、信号驱动 IO(极少用)、异步 IO(理想模型) IO 多路复用:select(位图,FD 上限 1024)、poll(动态数组,轮询)、epoll(Linux 首选,O (1) 事件驱动) 同步 vs 异步:同步需等待 IO 就绪 / 完成(阻塞 / 非阻塞 / IO 多路复用),异步无需等待(内核回调通知) 高并发模型:Reactor(事件驱动)、多线程 Reactor(主线程 epoll + 子线程池处理任务) 核心选择:百万级并发选「epoll + 线程池 + ET 模式」,中高并发选「epoll/poll + 有限线程」,低并发选「BIO + 线程池」 一、同步 IO 与异步 IO核心定义 同步 IO:线程发起 IO 请求后,必须等待 IO 操作(就绪或数据拷贝)完成才能继续执行,线程主动参与等待过程。 典型:阻塞 IO、非阻塞 IO、IO 多路复用(select/poll/epoll)。 异步 I...
并发编程:线程
核心要点速览 线程 vs 进程:进程是资源分配单位(独立内存),线程是调度单位(共享进程内存),线程通信成本更低 线程创建:std::thread支持函数、Lambda、函数对象三种方式 线程管理:join()等待回收、detach()分离(慎用)、joinable()检查状态 线程标识:std::this_thread::get_id()获取 ID,std::thread::id判断唯一性 线程状态:就绪、运行、阻塞、终止 常用接口: std::this_thread 命名空间提供 sleep_for、sleep_until、yield 等工具函数。 一、线程的概念1. 进程与线程的区别 特性 进程 (Process) 线程 (Thread) 定义 程序的一次执行实例,资源分配的最小单位。 进程内的执行单元,调度的最小单位。 资源 独立的代码、数据、堆栈空间。 共享进程的代码、全局数据,独立的栈和寄存器。 隔离 地址空间独立 (高隔离性)。 共享进程地址空间 (低隔离性)。 通信 进程间通信 (IPC),开销大。 直接共享数据,开销小。 开销 创建...
基础与语法与数据结构:运算符与表达式
核心要点速览 逻辑运算符(&&/||):支持短路求值,右操作数可能不执行 逗号运算符(,):按左到右执行多个表达式,返回最后一个值,优先级最低 右结合运算符:赋值运算符(=)、条件运算符(?:)、单目运算符,优先级相同时从右到左执行 一、逻辑运算符的短路求值(&& / ||)核心规则短路求值是逻辑运算符的优化特性,仅在必要时计算右操作数,直接影响代码执行结果。 &&(逻辑与):左操作数为false时,直接返回false,右操作数不执行。 ||(逻辑或):左操作数为true时,直接返回true,右操作数不执行。 常见场景(含副作用表达式) &&短路示例: 123int i = 0;bool res = (i == 1) && (++i); // 左为false,右++i不执行// 结果:res=false,i=0(而非1) ||短路示例: 123int j = 0;bool res = (j == 0) || (++j); // 左为true,右++j不执...
网路编程:网络基础
核心要点速览 协议栈:TCP/IP 四层模型(应用层→传输层→网络层→数据链路层) TCP vs UDP:TCP 面向连接、可靠流式;UDP 无连接、高效数据报 三次握手:建立 TCP 连接,确保双方收发能力正常;四次挥手:断开连接,释放全双工通道 TIME_WAIT:客户端第四次挥手后停留 2MSL,确保 ACK 送达、旧报文失效 Socket:网络编程接口,由 “IP + 端口” 唯一标识,TCP 需按固定流程(绑定 - 监听 - 连接 - 收发)编程 一、TCP/IP 四层模型 应用层:提供具体业务协议(HTTP、FTP、DNS),定义数据格式和交互逻辑 传输层:TCP/UDP,负责端到端(进程间)数据传输(可靠 / 高效) 网络层:IP 协议,负责跨网络路由转发(寻址) 数据链路层:处理物理介质上的帧传输(如以太网帧) 二、TCP 与 UDP 核心对比 对比维度 TCP(传输控制协议) UDP(用户数据报协议) 连接性 面向连接(三次握手建连,四次挥手断连) 无连接(直接发送,无需建连) 可靠性 可靠(重传、序...

