八股(一)https://blog.csdn.net/2401_82607598/article/details/159960625?fromshare=blogdetail&sharetype=blogdetail&sharerId=159960625&sharerefer=PC&sharesource=2401_82607598&sharefrom=from_link
https://blog.csdn.net/2401_82607598/article/details/160991619?fromshare=blogdetail&sharetype=blogdetail&sharerId=160991619&sharerefer=PC&sharesource=2401_82607598&sharefrom=from_link
对STL容器的理解
主要分成
- 顺序容器
- 关联容器,又分无序容器和有序容器
- 容器适配器
- 其他容器
看这个图
Linux常用命令
基本指令
- pwd,显示当前目录路径
- ls,查看文件和目录
- cd,切换目录
- mkdir,创建目录
- rmdir,删除空目录
- touch,创建空文件
- rm,删除文件或目录
- mv,重命名或移动文件/目录
- cp,复制文件或目录
文件查看命令
- cat,查看文件内容
- head,从文件头开始查看内容
- tail,从文件尾部开始查看内容
重定向指令
- >,覆盖写入
- >>,追加写入
时间日期指令,date,cal
用户管理和组管理,groupadd,groupdel
- useradd,新增用户
- userdel,删除用户
- id,查看用户信息
- su,切换用户
- whoami,查看当前用户
文件权限
- chmod,更改文件权限
- chown,改变文件或目录的拥有者
- umask,查看和修改新建时默认文件权限
网络管理命令
- ifconfig,查看网卡信息
- ping,测试与某台主机的连通性
- curl,用于发送HTTP请求
- host,查询ip相关的域名
- netstat,监测网络连接状态
进程相关命令
- ps,查看进程相关信息,常用选项。。。ps -aux
- kill、killall,停止杀死进程
- top,实时显示进程的信息
- pstree,以树的形式查看进程信息
压缩和解压缩
- zip,压缩文件或目录
- unzip,解压
- gzip,压缩单个文件
- gunzip,解压gzip压缩的文件
- tar,打包命令
搜索查找
- find,从指定目录下递归遍历各个子目录
- locate,定位整个系统的文件路径
- grep,文本搜索
- which,
- whereis
软件包管理
- yum list
- yum install
- yum remove
还有一些零碎的,vim编辑,man查看文档,help,shutdown关机
被问到Linux查看CPU、GPU
- lscpu,提供了CPU架构的详尽信息,包括类型、核心数、每个核心的线程数、缓存大小
- cat /proc/cpuinfo,查看/proc/cpuinfo文件,Linux系统中这个文件详细了解到每个CPU核心的参数
- dmidecode,提供硬件系统的详尽详细
- lspci,查询所有PCI设备的标准命令,配合grep可以过滤出显卡相关的信息lspci|grep -i vga
- glxinfo,获取OpenGL图形系统的详细信息,包括GPU的制造商、型号
https://blog.csdn.net/juluwangriyue/article/details/131957682?fromshare=blogdetail&sharetype=blogdetail&sharerId=131957682&sharerefer=PC&sharesource=2401_82607598&sharefrom=from_link
互斥锁和读写锁的区别
- 互斥锁:互斥锁加锁失败后,线程会释放CPU,给其他线程。
- 自旋锁:加锁失败后,线程会忙等待,直到它拿到锁。
- 读写锁:由读锁和写锁两部分组成,如果只读取共享资源用读锁加锁,如果要修改共享资源用写锁加锁。读写锁适用于能明确区分读操作和写操作的场景。
前面提到的互斥锁、自旋锁、读写锁,都是属于悲观锁。悲观锁做事比较悲观,它认为多线程同时修改共享资源的概率比较高,于是很容易出现冲突,所以访问共享资源前,先要上锁。那相反的,如果多线程同时修改共享资源的概率比较低,就可以采用乐观锁。
多数据的数据共享
多线程数据共享核心原则:保证线程安全,控制可见性,有序性,原子性
- 无锁方案(原子变量atomic、线程局部存储TLS)
- 互斥同步(主流方案mutex互斥锁、读写锁,最常用)搭配RAll智能锁lock_guard、unique_lock
- 消息队列/生产者消费者(解耦共享,规避临界区)
- 设计层规避(尽量少共享数据)
高并发内存池。线程局部存储(threadlocalstorage,简称TLS)是一种存储机制,它允许每个线程拥有自己的变量副本。每个线程可以无锁的获取自己的ThreadCache对象。
C++11之后,可以直接用C++ 关键字thread_local去做声明,就可以定义线程局部存储变量了,这样可以跨平台。
线程局部存储 TLS线程独有数据
数据名义上全局,实际每个线程一份副本,线程间完全不共享,天然安全。
#include <iostream>
#include <thread>
using namespace std;
thread_local int g_num = 0; // 每个线程独立副本
void func(int id) {
g_num = id;
cout << "线程" << id << " num = " << g_num << endl;
}
int main() {
thread t1(func, 1);
thread t2(func, 2);
t1.join();
t2.join();
return 0;
}
线程局部存储,配合单例模式和智能指针。。。
结合C++多线程场景,分核心方案、选型、代码示例、避坑要点,按面试/工程实用角度整理,聚焦多线程共享数据全套解法。
一、总体思路
多线程共享数据核心原则:保证线程安全 + 控制可见性、有序性、原子性 主要分四大类方案:
1. 无锁方案(原子变量、线程局部存储)
2. 互斥同步(互斥锁、读写锁,最常用)
3. 消息队列/生产者消费者(解耦共享,规避临界区)
4. 设计层面规避(尽量少共享数据) 二、方案详解 + 适用场景 + 代码
1. 优先方案:减少共享(最佳实践)
能不共享就不共享,从根源解决线程安全问题。
• 每个线程使用私有局部变量,不对外暴露
• 任务拆分,数据随任务走,而非全局共享
• 函数传参尽量值传递/右值引用,少用裸指针/全局引用 面试话术:多线程设计第一准则:数据私有化,弱化共享。 2. 线程局部存储 TLS:线程独有数据
数据名义上全局,实际每个线程一份副本,线程间完全不共享,天然安全。 C++ 关键字:thread_local
示例
#include <iostream>
#include <thread>
using namespace std;
thread_local int g_num = 0; // 每个线程独立副本
void func(int id) {
g_num = id;
cout << "线程" << id << " num = " << g_num << endl;
}
int main() {
thread t1(func, 1);
thread t2(func, 2);
t1.join();
t2.join();
return 0;
}
适用场景
• 每个线程需要独立的全局状态、计数器、缓存
• 完全不需要线程间数据交互
特点
• 无线程竞争、无锁、性能极高
• 数据不互通,无法用来做多线程数据交互 3. 轻量级:原子变量 std::atomic(简单数值共享)
针对单个整型、指针、布尔值共享,无锁,依靠CPU原子指令实现线程安全。 无需加锁,开销远低于互斥锁。
常用类型
std::atomic<int> / std::atomic<bool> / std::atomic<long> 等
示例(多线程计数)
#include <iostream>
#include <thread>
#include <atomic>
using namespace std;
atomic<int> g_cnt = 0; // 原子变量,线程安全
void add() {
for (int i = 0; i < 10000; ++i) {
g_cnt++; // 自增原子操作
}
}
int main() {
thread t1(add);
thread t2(add);
t1.join();
t2.join();
cout << "总数:" << g_cnt << endl; // 结果正确 20000
return 0;
}
适用 & 限制
✅ 适用:计数器、状态标志、开关、简单数值同步 ❌ 不适用:复合操作、结构体、对象、多条语句(如 if + 赋值 组合依然有竞态)
补充:内存序
默认 std::memory_order_seq_cst(顺序一致),追求极致性能可放宽内存序(面试了解即可)。 4. 主流方案:互斥锁 mutex(复杂共享数据)
多个线程读写对象、容器、多变量组合,使用互斥锁保护临界区,同一时刻仅一个线程访问。 搭配 RAII 智能锁 std::lock_guard / std::unique_lock,避免漏解锁。
基础示例(共享容器)
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
using namespace std;
vector<int> g_vec;
mutex g_mtx;
void write() {
for (int i = 0; i < 100; ++i) {
// RAII 上锁,出作用域自动解锁
lock_guard<mutex> lock(g_mtx);
g_vec.push_back(i);
}
}
void read() {
while (true) {
lock_guard<mutex> lock(g_mtx);
if (!g_vec.empty()) {
cout << g_vec.back() << " ";
break;
}
}
}
int main() {
thread t1(write);
thread t2(read);
t1.join();
t2.join();
return 0;
}
关键要点
1. 临界区尽量短小:只把读写共享数据的代码加锁,无关逻辑移出
2. 禁止锁内耗时操作(IO、sleep、网络),严重阻塞并发
3. 避免死锁:多锁保持固定加锁顺序、不嵌套锁 5. 读多写少专用:读写锁 shared_mutex
承接上一轮问答,读共享、写独占,高并发读场景大幅提升性能。
示例
#include <iostream>
#include <thread>
#include <shared_mutex>
#include <string>
using namespace std;
string g_config = "default";
shared_mutex g_rw_mtx;
// 读线程:共享锁(多线程同时读)
void read_config(int id) {
shared_lock<shared_mutex> lock(g_rw_mtx);
cout << "读线程" << id << ": " << g_config << endl;
}
// 写线程:独占锁(排他所有读写)
void write_config() {
unique_lock<shared_mutex> lock(g_rw_mtx);
g_config = "new setting";
cout << "写线程更新配置" << endl;
}
int main() {
thread t1(read_config, 1);
thread t2(read_config, 2);
thread t3(write_config);
t1.join(); t2.join(); t3.join();
return 0;
}
适用场景
• 配置数据、全局缓存、静态报表、查询远多于修改 6. 解耦方案:生产者/消费者 + 阻塞队列
不直接共享全局数据,用线程安全队列中转数据,线程间通过队列通信,彻底隔离临界区。 工程中高频用于:日志、任务队列、数据转发。
简易线程安全队列
#include <iostream>
#include <thread>
#include <mutex>
#include <queue>
#include <condition_variable>
using namespace std;
template<typename T>
class SafeQueue {
private:
queue<T> q;
mutable mutex mtx;
condition_variable cv;
public:
void push(T val) {
lock_guard<mutex> lock(mtx);
q.push(val);
cv.notify_one(); // 唤醒等待线程
}
bool pop(T& val) {
unique_lock<mutex> lock(mtx);
// 队空则等待
cv.wait(lock, [this](){ return !q.empty(); });
val = q.front();
q.pop();
return true;
}
};
SafeQueue<int> data_queue;
// 生产者
void producer() {
for (int i = 1; i <= 5; ++i) {
data_queue.push(i);
}
}
// 消费者
void consumer() {
int val;
while (data_queue.pop(val)) {
cout << "消费:" << val << endl;
}
}
int main() {
thread t1(producer);
thread t2(consumer);
t1.join();
t2.join();
return 0;
}
优势
• 线程解耦,读写分离,逻辑清晰
• 配合条件变量,实现阻塞等待,无忙等浪费CPU 三、方案选型速查表(面试直接背) 场景 推荐方案 优点 完全不需要数据互通、每个线程独立数据 thread_local 无锁、性能最高 单个数值/布尔、简单计数/状态 std::atomic 无锁、轻量 普通读写、数据结构/对象共享、读写均衡 std::mutex 互斥锁 简单通用、不易出错 读多写少(配置、缓存) std::shared_mutex 读写锁 高并发读性能好 线程间数据流转、任务分发、日志 阻塞队列(队列+互斥锁+条件变量) 解耦、架构清晰
四、通用避坑要点(面试高频考点)
1. 竞态条件:多条语句操作共享变量,必须加锁,原子变量只保护单条原子操作。
2. 临界区最小化:锁范围越小,并发越高。
3. 死锁防范:多锁顺序一致、不嵌套锁、不在锁内调用外部函数。
4. 可见性问题:多线程共享变量,不要依赖编译器优化,优先用锁/原子保证内存可见。
5. 拒绝裸全局变量:尽量封装成类,把锁和数据绑定在一起(封装线程安全类)。
6. 锁粒度选择:粗粒度锁(一把锁保护所有数据)简单但并发低;细粒度锁(多分锁)并发高但易死锁。 五、面试一句话总结
1. 能不共享就不共享,优先 thread_local 私有化数据;
2. 简单数值用原子变量无锁实现;
3. 常规对象/容器共享用互斥锁;
4. 读多写少场景改用读写锁提升并发;
5. 线程间数据流转,用阻塞队列解耦,是工程最优实践。
C++新标准新特性(后面补充
- auto
- nullptr
- for语法糖
- 列表初始化
- override
- delete
- default关键字
- 匿名函数
- 右值引用
- 线程类
- STL标准模板库
左值和右值,通俗话讲了。。move语句
左值右值都是表示数据的表达式。
左值具有地址,可以出现在赋值号左侧,可以取地址,变量、对象、数组元素都是左值。。
右值通常没有地址存储在寄存器或临时内存中,不能出现在赋值号的左侧,不能取地址(除非是绑定到const左值引用中),字面量、表达式计算结果都是右值。
- 左值,表示一个占据内存中可识别位置的一个对象,如变量名或解引用的指针,我们可以获取它的地址,可以给他赋值。
- 右值,如字面常量、表达式返回值、函数返回值。不能对变量或表达式取地址
左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。右值可以出现在赋值符号的右边,但不能在左边,右值不能取地址。
move用于将一个对象的资源移动到另一个对象,而不是拷贝资源。
指针和智能指针,指针是什么
git分支相关
三次握手和四次挥手(总结成通俗的话
python里面装饰器





![[C++]算法双指针 复写0-171主机测评](https://www.171host.com/wp-content/uploads/2026/09/20260910013601-6aa2098179e1b-220x150.png)
