在现代计算机中,多核 CPU 已经成为标配。多线程编程让你的程序能够同时执行多个任务,充分利用多核性能。C++11 引入了标准的线程库,让多线程编程变得更加简单和安全。
1. 什么是多线程?
1.1 单线程 vs 多线程
单线程:程序只有一个执行流,任务依次执行。
任务A → 任务B → 任务C
多线程:程序有多个执行流,任务可以并行执行。
线程1:任务A → 任务C
线程2:任务B →
1.2 并发 vs 并行
- 并发(Concurrency):多个任务交替执行,可能是单核 CPU
- 并行(Parallelism):多个任务真正同时执行,需要多核 CPU
1.3 为什么需要多线程?
- 提高性能:充分利用多核 CPU
- 响应性:后台任务不阻塞 UI
- 资源利用:等待 I/O 时执行其他任务
2. std::thread 基础
2.1 创建线程
cpp
#include <iostream>
#include <thread>
using namespace std;
void hello() {
cout << "Hello from thread!" << endl;
}
int main() {
thread t(hello); // 创建线程
t.join(); // 等待线程结束
cout << "Hello from main!" << endl;
return 0;
}
注意 :必须调用 join() 或 detach(),否则程序会崩溃。
2.2 join vs detach
cpp
#include <iostream>
#include <thread>
using namespace std;
void worker() {
cout << "Worker thread running" << endl;
}
int main() {
// 方式一:join - 等待线程结束
thread t1(worker);
t1.join(); // 主线程等待 t1 结束
// 方式二:detach - 分离线程
thread t2(worker);
t2.detach(); // t2 在后台独立运行
// 注意:detach 后不能再 join
// 主线程结束时,detach 的线程也会被强制结束
this_thread::sleep_for(chrono::milliseconds(100));
return 0;
}
2.3 传递参数
cpp
#include <iostream>
#include <thread>
#include <string>
using namespace std;
void printMessage(const string& msg, int count) {
for (int i = 0; i < count; i++) {
cout << msg << " " << i << endl;
}
}
int main() {
// 传递参数给线程函数
thread t(printMessage, "Hello", 3);
t.join();
return 0;
}
2.4 Lambda 表达式创建线程
cpp
#include <iostream>
#include <thread>
using namespace std;
int main() {
int x = 42;
// 使用 Lambda 创建线程
thread t([x]() {
cout << "x = " << x << endl;
});
t.join();
return 0;
}
2.5 成员函数作为线程入口
cpp
#include <iostream>
#include <thread>
using namespace std;
class Worker {
public:
void doWork(int id) {
cout << "Worker " << id << " is working" << endl;
}
};
int main() {
Worker worker;
// 成员函数需要传递对象指针
thread t(&Worker::doWork, &worker, 1);
t.join();
return 0;
}
3. 线程管理
3.1 std::thread 的生命周期
cpp
#include <iostream>
#include <thread>
using namespace std;
void worker() {
this_thread::sleep_for(chrono::seconds(1));
cout << "Worker done" << endl;
}
int main() {
thread t(worker);
cout << "Thread joinable: " << t.joinable() << endl; // 输出:1 (true)
t.join();
cout << "Thread joinable: " << t.joinable() << endl; // 输出:0 (false)
return 0;
}
3.2 RAII 管理线程
cpp
#include <iostream>
#include <thread>
using namespace std;
class ThreadGuard {
private:
thread& t;
public:
explicit ThreadGuard(thread& t) : t(t) {}
~ThreadGuard() {
if (t.joinable()) {
t.join(); // 析构时自动 join
}
}
// 禁止复制
ThreadGuard(const ThreadGuard&) = delete;
ThreadGuard& operator=(const ThreadGuard&) = delete;
};
void worker() {
cout << "Worker thread" << endl;
}
int main() {
thread t(worker);
ThreadGuard guard(t);
// 即使发生异常,也能保证线程被 join
throw runtime_error("Something went wrong");
return 0;
}
3.3 std::jthread(C++20)
C++20 引入了 jthread,自动在析构时 join:
cpp
#include <iostream>
#include <thread>
using namespace std;
void worker() {
cout << "Worker thread" << endl;
}
int main() {
jthread t(worker); // 自动 join
// 不需要手动 join
return 0;
}
4. 线程同步
4.1 问题:数据竞争
cpp
#include <iostream>
#include <thread>
using namespace std;
int counter = 0;
void increment() {
for (int i = 0; i < 100000; i++) {
counter++; // 非原子操作!
}
}
int main() {
thread t1(increment);
thread t2(increment);
t1.join();
t2.join();
// 结果不确定,可能小于 200000
cout << "Counter: " << counter << endl;
return 0;
}
4.2 std::mutex(互斥锁)
cpp
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
int counter = 0;
mutex mtx;
void increment() {
for (int i = 0; i < 100000; i++) {
lock_guard<mutex> lock(mtx); // 自动加锁和解锁
counter++;
}
}
int main() {
thread t1(increment);
thread t2(increment);
t1.join();
t2.join();
cout << "Counter: " << counter << endl; // 输出:200000
return 0;
}
4.3 lock_guard vs unique_lock
cpp
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
mutex mtx;
// lock_guard:简单场景
void simpleLock() {
lock_guard<mutex> lock(mtx);
// 临界区
} // 自动解锁
// unique_lock:需要更灵活的控制
void flexibleLock() {
unique_lock<mutex> lock(mtx);
// 临界区
lock.unlock(); // 手动解锁
// 做一些不需要锁的操作
lock.lock(); // 重新加锁
// 临界区
}
4.4 死锁
cpp
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
mutex mtx1, mtx2;
void thread1() {
lock_guard<mutex> lock1(mtx1);
this_thread::sleep_for(chrono::milliseconds(10));
lock_guard<mutex> lock2(mtx2); // 等待 mtx2
cout << "Thread 1 done" << endl;
}
void thread2() {
lock_guard<mutex> lock2(mtx2);
this_thread::sleep_for(chrono::milliseconds(10));
lock_guard<mutex> lock1(mtx1); // 等待 mtx1
cout << "Thread 2 done" << endl;
}
int main() {
thread t1(thread1);
thread t2(thread2);
t1.join(); // 死锁!程序卡住
t2.join();
return 0;
}
解决方案:
cpp
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
mutex mtx1, mtx2;
void thread1() {
// 同时锁定两个互斥锁
lock(mtx1, mtx2);
lock_guard<mutex> lock1(mtx1, adopt_lock);
lock_guard<mutex> lock2(mtx2, adopt_lock);
cout << "Thread 1 done" << endl;
}
void thread2() {
// 使用相同的顺序锁定
lock(mtx1, mtx2);
lock_guard<mutex> lock1(mtx1, adopt_lock);
lock_guard<mutex> lock2(mtx2, adopt_lock);
cout << "Thread 2 done" << endl;
}
int main() {
thread t1(thread1);
thread t2(thread2);
t1.join();
t2.join();
return 0;
}
5. 条件变量
5.1 基本用法
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
using namespace std;
queue<int> dataQueue;
mutex mtx;
condition_variable cv;
bool finished = false;
void producer() {
for (int i = 0; i < 10; i++) {
{
lock_guard<mutex> lock(mtx);
dataQueue.push(i);
cout << "Produced: " << i << endl;
}
cv.notify_one(); // 通知消费者
this_thread::sleep_for(chrono::milliseconds(100));
}
{
lock_guard<mutex> lock(mtx);
finished = true;
}
cv.notify_all();
}
void consumer() {
while (true) {
unique_lock<mutex> lock(mtx);
cv.wait(lock, []() { return !dataQueue.empty() || finished; });
while (!dataQueue.empty()) {
int data = dataQueue.front();
dataQueue.pop();
cout << "Consumed: " << data << endl;
}
if (finished && dataQueue.empty()) {
break;
}
}
}
int main() {
thread prod(producer);
thread cons(consumer);
prod.join();
cons.join();
return 0;
}
6. 原子操作
6.1 std::atomic
cpp
#include <iostream>
#include <thread>
#include <atomic>
using namespace std;
atomic<int> counter(0);
void increment() {
for (int i = 0; i < 100000; i++) {
counter++; // 原子操作
}
}
int main() {
thread t1(increment);
thread t2(increment);
t1.join();
t2.join();
cout << "Counter: " << counter << endl; // 输出:200000
return 0;
}
6.2 常用原子操作
cpp
#include <iostream>
#include <atomic>
using namespace std;
int main() {
atomic<int> val(0);
val.store(10); // 存储
int x = val.load(); // 加载
val++; // 自增
val--; // 自减
val += 5; // 加法
val.compare_exchange_strong(x, 20); // CAS 操作
cout << val << endl; // 输出:15
return 0;
}
7. 线程局部存储
7.1 thread_local
cpp
#include <iostream>
#include <thread>
using namespace std;
thread_local int localVar = 0;
void worker(int id) {
localVar = id;
this_thread::sleep_for(chrono::milliseconds(100));
cout << "Thread " << id << ": localVar = " << localVar << endl;
}
int main() {
thread t1(worker, 1);
thread t2(worker, 2);
t1.join();
t2.join();
// 每个线程有自己的 localVar 副本
return 0;
}
8. 异步操作
8.1 std::async 和 std::future
cpp
#include <iostream>
#include <future>
#include <chrono>
using namespace std;
int compute() {
this_thread::sleep_for(chrono::seconds(1));
return 42;
}
int main() {
// 异步执行
future<int> result = async(launch::async, compute);
cout << "Doing other work..." << endl;
// 获取结果(会阻塞直到完成)
int value = result.get();
cout << "Result: " << value << endl;
return 0;
}
8.2 packaged_task
cpp
#include <iostream>
#include <future>
#include <thread>
using namespace std;
int multiply(int a, int b) {
return a * b;
}
int main() {
packaged_task<int(int, int)> task(multiply);
future<int> result = task.get_future();
thread t(move(task), 6, 7);
cout << "Result: " << result.get() << endl; // 输出:42
t.join();
return 0;
}
9. 实际应用
9.1 线程池
cpp
#include <iostream>
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
using namespace std;
class ThreadPool {
private:
vector<thread> workers;
queue<function<void()>> tasks;
mutex mtx;
condition_variable cv;
bool stop;
public:
ThreadPool(int numThreads) : stop(false) {
for (int i = 0; i < numThreads; i++) {
workers.emplace_back([this]() {
while (true) {
function<void()> task;
{
unique_lock<mutex> lock(mtx);
cv.wait(lock, [this]() { return stop || !tasks.empty(); });
if (stop && tasks.empty()) return;
task = move(tasks.front());
tasks.pop();
}
task();
}
});
}
}
~ThreadPool() {
{
lock_guard<mutex> lock(mtx);
stop = true;
}
cv.notify_all();
for (auto& worker : workers) {
worker.join();
}
}
template<class F>
void enqueue(F&& f) {
{
lock_guard<mutex> lock(mtx);
tasks.emplace(forward<F>(f));
}
cv.notify_one();
}
};
int main() {
ThreadPool pool(4);
for (int i = 0; i < 8; i++) {
pool.enqueue([i]() {
cout << "Task " << i << " running in thread "
<< this_thread::get_id() << endl;
this_thread::sleep_for(chrono::milliseconds(100));
});
}
this_thread::sleep_for(chrono::seconds(1));
return 0;
}
10. 常见陷阱
10.1 忘记 join 或 detach
cpp
// 错误
thread t(worker);
// 程序结束时会崩溃
// 正确
thread t(worker);
t.join(); // 或 t.detach()
10.2 传递引用参数
cpp
void modify(int& x) {
x = 100;
}
int main() {
int val = 42;
// thread t(modify, val); // 错误!
thread t(modify, ref(val)); // 使用 ref
t.join();
cout << val << endl; // 输出:100
}
10.3 数据竞争
始终确保共享数据的访问是同步的。
11. 总结
C++ 多线程编程的核心概念:
- std::thread:创建和管理线程
- std::mutex:互斥锁,保护共享数据
- std::condition_variable:线程间通信
- std::atomic:原子操作,无锁编程
- std::async:异步任务
最佳实践:
- 使用 RAII 管理线程生命周期
- 优先使用
lock_guard或unique_lock - 避免死锁:固定加锁顺序
- 尽量使用原子操作代替互斥锁
- C++20 使用
jthread简化线程管理
下一节我们将学习智能指针与多线程的结合使用。