C++11引入了多线程支持,使得在标准库中直接使用线程和同步机制成为可能。在多线程编程中,你可以使用多线程来并发地执行任务,以提高程序性能,尤其是在处理I/O密集型或计算密集型任务时。
多线程的基本概念
- 线程(Thread):是程序执行的基本单位。在多线程编程中,一个程序可以包含多个并发执行的线程。
- 主线程(Main Thread):通常是程序的入口点,也就是
main()
函数所在的线程。创建的其他线程称为子线程(Worker Thread)。 - 数据同步:多线程访问共享数据时,需要确保同步,以避免数据竞争(Race Condition)问题。
使用 C++ 多线程的基本步骤
- 创建线程
- 启动线程执行任务
- 同步线程或等待线程完成
- 处理线程中的共享数据
示例结构
C++ 多线程的主要类是 std::thread
,它提供了线程的基本操作。C++11 提供了锁机制来管理线程同步,比如 std::mutex
、std::lock_guard
等。
1. 创建和启动线程
最简单的方式是通过 std::thread
创建一个线程,并传递要执行的函数或方法。
示例1:创建一个简单的线程
#include <iostream>
#include <thread>
// 线程执行的函数
void myTask() {
std::cout << "Thread is running!" << std::endl;
}
int main() {
// 创建并启动一个线程
std::thread t(myTask);
// 等待线程执行完成
t.join();
std::cout << "Main thread finished." << std::endl;
return 0;
}
解释:
std::thread t(myTask);
:创建并启动一个线程,myTask
函数在新的线程中执行。t.join();
:主线程等待子线程执行完成。
2. 传递参数给线程
你可以传递参数给线程函数,C++11 提供了自动参数传递的机制。
示例2:传递参数给线程函数
#include <iostream>
#include <thread>
// 带参数的线程函数
void printNumbers(int start, int end) {
for (int i = start; i <= end; ++i) {
std::cout << "Number: " << i << std::endl;
}
}
int main() {
// 创建线程并传递参数
std::thread t(printNumbers, 1, 5);
// 等待线程执行完成
t.join();
return 0;
}
解释:
std::thread t(printNumbers, 1, 5);
:线程函数printNumbers
需要两个参数,1 和 5。
3. 使用 lambda 表达式创建线程
C++11 支持 lambda 表达式,你可以直接在创建线程时定义任务。
示例3:使用 lambda 创建线程
#include <iostream>
#include <thread>
int main() {
// 使用 lambda 表达式创建线程
std::thread t([] {
for (int i = 0; i < 5; ++i) {
std::cout << "Lambda thread: " << i << std::endl;
}
});
// 等待线程执行完成
t.join();
return 0;
}
4. 等待线程完成 (join
) 和分离线程 (detach
)
join()
:主线程等待子线程完成任务。detach()
:子线程与主线程分离,主线程不等待子线程结束,子线程将在后台运行并独立结束。
示例4:使用 detach()
分离线程
#include <iostream>
#include <thread>
#include <chrono>
void backgroundTask() {
for (int i = 0; i < 5; ++i) {
std::cout << "Background task running..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟耗时操作
}
}
int main() {
std::thread t(backgroundTask);
// 分离线程,让它在后台独立运行
t.detach();
std::cout << "Main thread continues..." << std::endl;
// 主线程继续工作,子线程在后台运行
std::this_thread::sleep_for(std::chrono::seconds(6)); // 让主线程等待一会儿
std::cout << "Main thread finished." << std::endl;
return 0;
}
解释:
t.detach();
:主线程和子线程分离,主线程不再等待子线程,子线程会在后台运行并自动结束。
5. 线程同步
当多个线程访问共享数据时,必须同步它们的操作,以避免数据竞争问题。C++11 提供了 std::mutex
(互斥锁)来解决这个问题。
示例5:使用 std::mutex
同步线程
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx; // 互斥锁保护共享资源
int counter = 0;
void incrementCounter() {
for (int i = 0; i < 1000; ++i) {
std::lock_guard<std::mutex> lock(mtx); // 加锁
++counter; // 修改共享数据
}
}
int main() {
std::thread t1(incrementCounter);
std::thread t2(incrementCounter);
t1.join();
t2.join();
std::cout << "Final counter value: " << counter << std::endl;
return 0;
}
解释:
std::mutex mtx;
:创建互斥锁mtx
,防止多个线程同时修改counter
。std::lock_guard<std::mutex> lock(mtx);
:自动加锁和解锁机制,确保每次只有一个线程能访问counter
。
6. 使用 std::future
和 std::async
std::async
可以用来启动异步任务,并返回一个 std::future
对象,供主线程查询任务的执行结果。
示例6:使用 std::async
启动异步任务
#include <iostream>
#include <future>
int task(int a, int b) {
return a + b;
}
int main() {
// 使用 std::async 启动异步任务,并获取 std::future 对象
std::future<int> result = std::async(std::launch::async, task, 10, 20);
// 获取异步任务的返回值
int value = result.get();
std::cout << "Result: " << value << std::endl;
return 0;
}
解释:
std::async
:启动异步任务,指定任务为task(10, 20)
。result.get()
:获取异步任务的执行结果。
7. 处理多线程的共享数据和竞争条件
竞争条件(Race Condition)发生在多个线程同时访问和修改共享资源时,结果依赖于线程的执行顺序。
避免竞争条件的关键:
- 互斥锁(Mutex):用来保护共享资源。
- 原子操作:通过
std::atomic
提供的原子操作来避免锁的使用。
示例7:使用 std::atomic
避免竞争条件
#include <iostream>
#include <thread>
#include <atomic>
std::atomic<int> counter(0); // 原子操作
void incrementCounter() {
for (int i = 0; i < 1000; ++i) {
++counter; // 原子操作,不需要锁
}
}
int main() {
std::thread t1(incrementCounter);
std::thread t2(incrementCounter);
t1.join();
t2.join();
std::cout << "Final counter value: " << counter << std::endl;
return 0;
}
解释:
std::atomic<int> counter(0);
:原子变量counter
,可以在线程之间安全递增,而不需要锁。
8. 线程间通信
线程间通信的常用方法是使用条件变量(std::condition_variable
)来让一个线程等待另一个线程的信号。
示例8:使用 std::condition_variable
进行线程间通信
#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 proceeding..." << std::endl;
}
void notify() {
std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟其他任务
{
std::lock_guard<std::mutex