八股临时总结

文章目录

一、原子操作的内部屏障

1、原子操作的功能

(1)保证这个变量的读写不可被打断;

(2)保证操作前后的内存访问顺序不会被编译器或CPU重排序;

2、原子内部屏障

(1)CAS(无锁同步机制,通过比较内存中的值是否等于期望值,如果相等则更新为新值,否则失败并重试)

(2)memory-barrier(内存屏障 )防止CPU和编译器为了优化,把代码执行顺序乱掉

release/acquire通常通过memory barrier实现

acquire和release

Acquire Release
保证当前线程读到的数据是最新的 保证本线程对数据的修改是其他线程可见的
cpp 复制代码
#include <atomic>
#include <iostream>
#include <thread>

std::atomic<bool> ready{false};
int data = 0;

void producer() {
    data = 42;          // 步骤 1: 准备数据
    // Release: 保证 data = 42 绝对不会被重排到这句代码的【后面】
    ready.store(true, std::memory_order_release); 
}

void consumer() {
    // Acquire: 保证读到 true 之后,后续的代码绝对不会被重排到这句代码的【前面】
    while (!ready.load(std::memory_order_acquire)) {
        // 等待
    }
    
    // 步骤 3: 读取数据
    // 绝对安全!因为 Acquire 和 Release 配对,
    // producer 中在 release 之前的所有修改(data=42),
    // 在 consumer 中 acquire 之后必然可见!
    std::cout << data << std::endl; // 永远输出 42
}

int main() {
    std::thread t1(producer);
    std::thread t2(consumer);
    t1.join();
    t2.join();
    return 0;
}

二、虚函数表实现原理

2.1 为什么需要虚函数?

C++默认函数调用都是静态绑定:

cpp 复制代码
class Base {
public:
    void func(){
        cout<<"Base";
    }
};

class Derived: public Base {
public:
    void func(){
        cout<<"Derived";
    }
};


Base* ptr = new Derived();
ptr->func();

输出:Base

因为在编译阶段就已经确定调用了Base::func

如果希望:利用基类Base类型指针调用派生类func,则需要虚函数

cpp 复制代码
class Base{
public:
	virtual void func(){
		cout<<"Base";
	}
};

这就是多态!

2.2 虚函数表是什么?

当一个类包含虚函数时,编译器会给这个类增加一个隐藏成员:虚函数表;

调用过程:

cpp 复制代码
Base* p = new Derived();

p->func();
  1. 根据p找到对象
  2. 找到对象里的vptr
  3. 根据vptr找到vtable
  4. 找到对应函数地址
  5. 调用派生类Derived::func()

通过虚函数表记录,实现动态绑定;

2.3 虚函数表的开销?

2个:

(1)对象增加一个指针:vptr(8字节)

(2)多一次间接寻址:加载 vptr -> 加载 func address -> 调用

2.4 析构函数为什么经常写virtual?

普通的析构函数,在通过基类ptr执行析构函数时,不会将其派生类对象析构掉,会造成:内存泄露。

回答总结:

  • C++虚函数通过vptr和vtable实现运行时多态。包含虚函数的对象内部维护一个虚函数表指针,指向存储虚函数地址的表。
  • 当通过基类指针调用虚函数时,会根据vptr查找到其真实函数的地址,从而调用派生类实现;

三、智能指针使用场景和内存管理

普通指针会存在忘记delete的问题,所以利用智能指针方便管理(直接自动管理)

类型 特点 场景
unique_ptr 唯一所有权 资源管理 :谁创建谁释放
shared_ptr 共享所有权 多个模块共享,存在问题:多线程同步
weak_ptr 观察,不拥有 解决循环引用

四、多线程同步机制

多个线程同时访问共享资源导致数据竞争

重量级方式:

4.1 mutex互斥锁

cpp 复制代码
std::mutex m;


m.lock();

count++;

m.unlock();

4.2 atomic原子操作

针对简单变量:

cpp 复制代码
std::atomic<int> count;

count++;

内部支持CAS

读取旧值

比较是否改变

如果没有改变

更新

否则重试

4.3 生产者、消费者模式

消费者:没有数据就wait()

生产者:开始生产就notify()

4.4 semaphore信号量

控制资源数量

例如:GPU任务队列

acquire()获取

执行任务

release()释放

相关推荐
xvhao20132 小时前
T750414 【游戏】计算24点 题解
数据结构·c++·算法·游戏
草莓熊Lotso3 小时前
【LangChain】核心组件详解:文档加载器(Document Loaders)
开发语言·c++·python·langchain·软件工程
ysa0510303 小时前
优先队列贪心dp
c++·笔记·算法·板子
草莓熊Lotso4 小时前
【Linux网络】深入理解Linux IO多路复用:select服务器完善、内核原理与poll实战
linux·运维·服务器·c语言·网络·c++
Andy4 小时前
Cpp进阶语法详解
c++
此生决int5 小时前
深入理解C++系列(04)——类和对象(下)
开发语言·c++
2601_9545267515 小时前
【工业传感与算法实战】温漂补偿与零点抗漂破局:基于二阶多项式拟合的 C/C++ 边缘校准算法,深度拆解“压力变送器什么牌子好”的技术硬指标
c语言·c++·算法
code_pgf16 小时前
`unordered_map` 详解
c++
一拳一个呆瓜17 小时前
【STL】iostream 编程:检测提取操作产生的错误
c++·stl