文章

C++多线程基础

C++多线程基础

C++多线程基础

1. 多线程基础

多线程是指一个程序中同时运行多个执行流(线程),能够充分利用多核CPU,提高程序并发性和效率。C++11 标准引入了官方的多线程支持,主要在 <thread>, <mutex>, <condition_variable> 等头文件中提供相关API。

2. 主要类和组件

2.1 std::thread

  • 表示一个线程对象。
  • 构造时传入线程执行函数和参数。
  • 线程启动后自动并发运行。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <thread>

void func() {
    std::cout << "Hello from thread!" << std::endl;
}

int main() {
    std::thread t(func);  // 创建并启动线程t执行func
    t.join();             // 等待线程t执行完毕
    return 0;
}
  • join():等待线程结束,阻塞主线程直到子线程完成。
  • detach():使线程与主线程分离,线程后台运行,不能等待。

2.2 线程参数传递

  • 线程函数可以带参数。
  • std::thread 构造函数可传入参数,会完美转发给线程函数。

示例:

1
2
3
4
5
6
7
8
void printNum(int x) {
    std::cout << "Number: " << x << std::endl;
}

int main() {
    std::thread t(printNum, 10);
    t.join();
}

2.3 线程返回值

std::thread 函数本身不支持直接返回值。

若需要线程返回值,一般用:

  • std::promisestd::future
  • 或者 std::async

2.4 std::mutex(互斥锁)

用于保护共享资源,防止数据竞争。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <mutex>
#include <thread>
#include <iostream>

int counter = 0;
std::mutex mtx;

void increment() {
    for(int i = 0; i < 1000; ++i) {
        std::lock_guard<std::mutex> lock(mtx);
        ++counter;
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);
    t1.join();
    t2.join();
    std::cout << "Counter = " << counter << std::endl;  // 正确值2000
}
  • std::lock_guard 是RAII风格的锁,作用域结束自动解锁。
  • mutex 保证同一时间只有一个线程访问被保护代码段。

2.5 std::unique_lock

lock_guard 更灵活,支持手动加锁、解锁、延迟加锁等。

2.6 std::condition_variable(条件变量)

用于线程间通知和等待。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <condition_variable>
#include <mutex>
#include <thread>
#include <iostream>

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 proceed\n";
}

int main() {
    std::thread t(worker);

    {
        std::lock_guard<std::mutex> lock(mtx);
        ready = true;
    }
    cv.notify_one();  // 通知worker线程

    t.join();
}

3. 线程的生命周期管理

  • 创建线程后,必须调用 join()detach(),否则程序会异常终止。
  • join() 阻塞等待线程结束。
  • detach() 线程独立运行,主线程不等待。

4. 线程同步和竞态条件

  • 多线程共享数据时,必须使用锁(如mutex)避免竞态条件。
  • 竞态条件会导致数据不一致和未定义行为。

5. std::asyncstd::future

  • std::async 可以异步启动任务,自动管理线程。
  • std::future 可用于获取异步任务返回值。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
#include <future>
#include <iostream>

int compute() {
    return 42;
}

int main() {
    std::future<int> fut = std::async(std::launch::async, compute);
    int result = fut.get();  // 阻塞等待结果
    std::cout << "Result: " << result << std::endl;
}

6. 线程相关的常用函数和特性

  • std::this_thread::sleep_for():线程睡眠指定时间
  • std::this_thread::get_id():获取当前线程id
  • std::thread::hardware_concurrency():返回系统支持的并发线程数(硬件线程数)

7. 总结

组件功能备注
std::thread创建线程需手动 join 或 detach
std::mutex互斥锁保护共享数据避免竞态
std::lock_guard简单锁管理,RAII作用域自动加解锁
std::unique_lock更灵活锁管理支持延迟加锁、解锁
std::condition_variable线程间等待和通知用于条件同步
std::async/future异步任务和返回值方便简洁地获取结果
本文由作者按照 CC BY 4.0 进行授权