多线程开发

基本线程操作

1. 创建线程

#include <iostream>
#include <thread>

void threadFunc() {
    std::cout << "子线程正在执行..." << std::endl;
}

int main() {
    std::thread t(threadFunc);  // 创建并启动线程
    std::cout << "主线程等待子线程..." << std::endl;
    t.join();  // 主线程阻塞,等待 t 执行完毕
    std::cout << "子线程已结束,主线程继续。" << std::endl;
    return 0;
}
  • t.join() 会阻塞当前线程(通常是主线程或调用 join 的线程),直到线程 t 执行完毕。

  • 调用 join() 后,主线程会暂停,等待子线程 t 完成任务后才会继续执行。

关键点

  • 同步线程:确保主线程等待子线程完成后再继续或退出。

  • 资源清理:join() 会释放线程 t 的系统资源(如线程 ID、栈内存等)。

  • 必须调用:如果线程对象 t 是 joinable 的(即已关联线程且未 join 或 detach),在销毁前必须调用 join() 或 detach(),否则程序会调用 std::terminate() 终止。

注意事项

  • 如果忘记调用 join() 或 detach(),程序会异常终止。

  • 不能对同一个线程多次调用 join()(会导致 std::system_error)。

  • 可以通过 t.joinable() 检查线程是否需要 join。

对比 detach()

  • t.detach():分离线程,让线程独立运行,主线程不再等待(失去对线程的控制权)。

  • t.join():等待线程结束,保持控制权。

2. 带参数的线程函数

void printMessage(const std::string& message) {
    std::cout << message << std::endl;
}

int main() {
    std::thread t(printMessage, "Hello from thread with args!");
    t.join();
    return 0;
}

3. 分离线程

std::thread t(backgroundTask);
t.detach();  // 线程将独立运行,主线程不再等待

线程同步

1. 互斥锁(Mutex)
作用:防止多个线程同时访问共享资源,确保同一时间只有一个线程可以访问临界区(Critical Section)。
C++ 标准库支持:std::mutex, std::lock_guard, std::unique_lock

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;  // 全局互斥锁
int shared_data = 0;

void increment() {
    std::lock_guard<std::mutex> lock(mtx);  // 自动加锁,离开作用域解锁
    shared_data++;  // 临界区
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);
    t1.join();
    t2.join();
    std::cout << "Shared data: " << shared_data << std::endl;  // 输出 2
    return 0;
}
  • std::lock_guard 是 RAII 风格锁,自动管理锁的生命周期。

  • std::unique_lock 更灵活,支持手动 lock() 和 unlock()。

2. 条件变量(Condition Variable)
作用:让线程等待某个条件成立,避免忙等待(Busy Waiting),通常与互斥锁配合使用。
C++ 标准库支持:std::condition_variable
成员函数:

  • wait(lock, predicate) :阻塞当前线程,直到被唤醒且 predicate 返回 true(防止虚假唤醒)。
  • notify_one() :随机唤醒一个等待的线程。
  • notify_all() :唤醒所有等待的线程。
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void worker() {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, [] { return ready; });  // 等待 ready == true
    std::cout << "Worker thread is processing..." << std::endl;
}

int main() {
    std::thread t(worker);
    { 
        std::lock_guard<std::mutex> lock(mtx);
        ready = true;  // 修改条件
    }
    cv.notify_one();  // 通知等待的线程
    t.join();
    return 0;
}
  • cv.wait() 会释放锁并进入等待状态,直到被 notify_one() 或 notify_all() 唤醒。

  • 防止虚假唤醒(Spurious Wakeup),通常搭配 while 或 predicate 检查条件。

3. 原子操作(Atomic Operations)
作用:对基本数据类型(如 int, bool)提供无锁(Lock-Free)的线程安全操作。
C++ 标准库支持:std::atomic<T>

#include <iostream>
#include <thread>
#include <atomic>

std::atomic<int> counter(0);

void increment() {
    counter++;  // 原子操作,无需锁
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);
    t1.join();
    t2.join();
    std::cout << "Counter: " << counter << std::endl;  // 输出 2
    return 0;
}

4. 读写锁(Read-Write Lock)
作用:允许多个线程同时读,但写操作独占资源(适用于读多写少的场景)。
C++ 标准库支持:std::shared_mutex(C++17)

#include <iostream>
#include <thread>
#include <shared_mutex>

std::shared_mutex rw_mutex;
int data = 0;

void reader() {
    std::shared_lock<std::shared_mutex> lock(rw_mutex);  // 共享读锁
    std::cout << "Read data: " << data << std::endl;
}

void writer() {
    std::unique_lock<std::shared_mutex> lock(rw_mutex);  // 独占写锁
    data++;
}

int main() {
    std::thread readers[3] = {std::thread(reader), std::thread(reader), std::thread(reader)};
    std::thread writer_thread(writer);
    for (auto& t : readers) t.join();
    writer_thread.join();
    return 0;
}
  • 读锁(shared_lock)允许多线程并发读。

  • 写锁(unique_lock)独占资源,阻塞所有读写操作。

5. 信号量(Semaphore)
作用:控制同时访问资源的线程数量(C++20 引入 std::counting_semaphore)。

#include <iostream>
#include <thread>
#include <semaphore>

std::counting_semaphore<5> sem(5);  // 允许最多 5 个线程同时访问

void worker(int id) {
    sem.acquire();  // 获取信号量
    std::cout << "Thread " << id << " is working..." << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    sem.release();  // 释放信号量
}

int main() {
    std::thread threads[10];
    for (int i = 0; i < 10; i++) {
        threads[i] = std::thread(worker, i);
    }
    for (auto& t : threads) t.join();
    return 0;
}
  • 适用于限流场景(如线程池、数据库连接池)。

6. 屏障(Barrier)
作用:让多个线程在某个点同步,等待所有线程到达后再继续(C++20 引入 std::barrier)。

#include <iostream>
#include <thread>
#include <barrier>

std::barrier sync_point(3);  // 等待 3 个线程

void worker(int id) {
    std::cout << "Thread " << id << " started" << std::endl;
    sync_point.arrive_and_wait();  // 等待其他线程
    std::cout << "Thread " << id << " continued" << std::endl;
}

int main() {
    std::thread t1(worker, 1);
    std::thread t2(worker, 2);
    std::thread t3(worker, 3);
    t1.join(); t2.join(); t3.join();
    return 0;
}
  • 适用于分阶段并行计算(如 MapReduce)。

总结

同步方式 适用场景 C++ 标准支持
互斥锁(Mutex) 保护共享数据,避免竞态条件 C++11
条件变量 线程间事件通知(生产者-消费者模型) C++11
原子操作 简单变量的无锁操作 C++11
读写锁 读多写少的场景 C++17
信号量 限流(如线程池) C++20
屏障 多线程分阶段同步 C++20
posted @ 2025-08-07 12:12  灰灰奋斗录  阅读(10)  评论(0)    收藏  举报