C++八股2

多线程编程

锁类型

  1. 互斥锁
std::mutex mtx;
mtx.lock();
mtx.unlock();
  1. 递归锁
// 允许同一线程多次锁定同一个互斥锁,而不会导致死锁。
// 适合递归函数或需要多次锁定的场景。
std::recursive_mutex rmtx;
rmtx.lock();
rmtx.lock(); // 同一线程可以多次锁定
rmtx.unlock();
rmtx.unlock();
  1. 读写锁(C++17)
std::shared_mutex smtx;
smtx.lock_shared();  // 共享锁(读)
smtx.unlock_shared();
smtx.lock();         // 独占锁(写)
smtx.unlock();
  1. 定时锁
std::timed_mutex tmtx;
if (tmtx.try_lock_for(std::chrono::seconds(1))) {
    // 加锁成功
    tmtx.unlock();
}
  1. 无锁
std::atomic<int> counter{0};
counter.fetch_add(1); // 原子加操作

线程池设计: 如何设计一个高效的线程池?任务队列如何实现?

线程池的大小确定:

    1. CPU 密集型任务(N+1): 任务消耗主要是 CPU 资源, 将线程数设置 N(CPU 核心数) + 1, 比核心数多出一个线程是为了放置线程偶发的缺页中断, 或者其他原因的任务暂停带来的影响。一旦任务暂停, CPU 就会处于空闲状态,多出来的一个线程就可以充分利用 CPU 的空闲时间.
    1. I/O 密集型(2N): 系统大部分时间用来处理 I/O 交互, 而线程在处理 I/O 的时间段内不会占用 CPU 来处理, 因此可以设置线程池大小为 2N, 这样可以充分利用 CPU 的空闲时间, 提高系统的并发处理能力.

线程创建和销毁的开销主要原因:

  • 内核资源分配: 每个线程需要分配内核栈, 线程控制块,涉及系统调用.
  • 内存分配: 线程栈空间(1~2MB/线程)
  • 调度和同步: 线程创建和销毁时, 操作系统需要维护调度队列和同步机制
  • 上下文切换: 频繁创建/销毁会导致更多的上下文切换.

多线程通信的方式

  1. 共享内存, 需要同步机制保护
// 多个线程共享同一内存区域, 通过互斥锁(mutex)保护数据一致性
#include <iostream>
#include <thread>
#include <mutex>

int shared_data = 0;         // 共享内存
std::mutex mtx;              // 互斥锁

void writer() {
    std::lock_guard<std::mutex> lock(mtx);
    shared_data = 42;        // 写共享数据
    std::cout << "Writer set shared_data = 42" << std::endl;
}

void reader() {
    std::lock_guard<std::mutex> lock(mtx);
    std::cout << "Reader get shared_data = " << shared_data << std::endl;
}

int main() {
    std::thread t1(writer);
    std::thread t2(reader);
    t1.join();
    t2.join();
    return 0;
}
  1. 条件变量, 用于线程间的等待和通知
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

int shared_data = 0;
std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void producer() {
    std::unique_lock<std::mutex> lock(mtx);
    shared_data = 42;
    ready = true;
    cv.notify_one(); // 通知等待的线程
    std::cout << "Producer set shared_data = 42" << std::endl;
}

void consumer() {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, []{ return ready; }); // 等待条件成立
    std::cout << "Consumer get shared_data = " << shared_data << std::endl;
}

int main() {
    std::thread t1(producer);
    std::thread t2(consumer);
    t1.join();
    t2.join();
    return 0;
}
  1. 无锁的轻量级通信
#include <atomic>

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

// 线程1
void producer() {
    counter.store(42);
    ready.store(true);
}

// 线程2
void consumer() {
    while (!ready.load()) {
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }
    int value = counter.load();
}
  1. 信号量
#include <semaphore>

std::counting_semaphore<10> sem(3); // 最多3个线程同时访问

void worker() {
    sem.acquire(); // 获取信号量
    // 执行工作
    sem.release(); // 释放信号量
}
  1. 异步结果传递
#include <future>

std::promise<int> prom;
std::future<int> fut = prom.get_future();

// 生产者线程
void producer() {
    int result = 42;
    prom.set_value(result);
}

// 消费者线程
void consumer() {
    int value = fut.get(); // 阻塞等待结果
}

多线程造成的崩溃问题

不等待线程结束, 直接销毁对象, 可能会导致下面的问题

  • 访问已释放的内存: 工作线程还在访问变量
  • 未定义行为: 线程还在运行时销毁对象会导致程序崩溃
  1. 访问已经释放的内存:
class DataProcessor {
public:
    int data = 42;
    void process() {
        while(running) {
            std::cout << data << std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }
    }
private:
    std::atomic<bool> running{true};
}

void dangerous_usage() {
    DataProcessor* processor = new DataProcessor();
    std::thread worker(&DataProcessor::process, processor);
    
    delete processor;  // 危险!线程还在运行
    // worker.join();  // 忘记等待线程结束
}


// 解决办法, 基于类 RAII 机制
class SafeDataProcessor {
public:
    SafeDataProcessor() : running(true) {}
    
    ~SafeDataProcessor() {
        stop();  // 析构时确保线程停止
    }
    
    void start() {
        worker_thread = std::thread(&SafeDataProcessor::process, this);
    }
    
    void stop() {
        running = false;
        if (worker_thread.joinable()) {
            worker_thread.join();  // 等待线程结束
        }
    }
    
private:
    void process() {
        while (running) {
            std::cout << data << std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }
    }
    
    int data = 42;
    std::atomic<bool> running;
    std::thread worker_thread;
};
  1. 栈溢出
// 线程栈空间不足, 递归调用或大型局部变量时

Cpp 中如何判断代码在那个线程中执行


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值