文章目录
C++ 中的线程是指程序中能够独立执行的一条控制流。线程允许在同一个进程中并发运行多个任务,从而提高程序的性能和响应性。C++11 标准引入了对线程的原生支持,通过 <thread>
标准库提供了一套工具来管理线程。
1. 什么是线程
线程是程序执行的基本单位,多个线程可以共享同一进程的资源(如内存、文件句柄等)。线程的使用场景包括:
- 多任务并行处理(如同时处理用户输入和后台计算)。
- 提高程序性能(利用多核 CPU)。
- 异步操作(如非阻塞 I/O)。
2. C++ 中的线程库
C++ 标准库中的线程功能由头文件 <thread>
提供,主要包括:
std::thread
:用于创建和管理线程。std::mutex
:用于线程同步,防止数据竞争。std::condition_variable
:用于线程间的条件通知。std::future
和std::promise
:用于线程间的结果传递。
3. 创建线程
基本用法
#include <iostream>
#include <thread>
void task() {
std::cout << "Hello from thread!" << std::endl;
}
int main() {
std::thread t(task); // 创建并启动线程
t.join(); // 等待线程完成
return 0;
}
说明:
std::thread t(task)
:启动线程t
,执行函数task
。t.join()
:主线程等待子线程完成。如果没有调用join()
或detach()
,程序会报错。
使用 Lambda 表达式
#include <iostream>
#include <thread>
int main() {
std::thread t([] {
std::cout << "Hello from Lambda thread!" << std::endl;
});
t.join();
return 0;
}
使用类成员函数
#include <iostream>
#include <thread>
class Task {
public:
void operator()() const {
std::cout << "Hello from class thread!" << std::endl;
}
};
int main() {
Task task;
std::thread t(task); // 使用类的调用运算符
t.join();
return 0;
}
4. 管理线程
join
和 detach
join()
:等待线程执行完成。线程执行完成前,主线程会被阻塞。detach()
:将线程与主线程分离,线程在后台继续运行。分离的线程无法再被主线程管理。
std::thread t(task);
t.detach(); // t 独立运行
检查线程是否可加入
if (t.joinable()) {
t.join();
}
5. 数据共享与同步
数据竞争问题
多个线程共享数据时,可能会发生数据竞争(多个线程同时访问和修改同一资源)。
#include <iostream>
#include <thread>
int counter = 0;
void increment() {
for (int i = 0; i < 100000; ++i) {
++counter;
}
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Counter: " << counter << std::endl; // 结果可能不正确
return 0;
}
使用互斥锁 (std::mutex
)
互斥锁可以防止数据竞争。
#include <iostream>
#include <thread>
#include <mutex>
int counter = 0;
std::mutex mtx;
void increment() {
for (int i = 0; i < 100000; ++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; // 结果正确
return 0;
}
死锁与避免
使用多个互斥锁时可能会发生死锁。可以使用 std::lock
同时锁定多个资源。
std::lock(mutex1, mutex2);
6. 条件变量
条件变量用于线程间的同步,使一个线程等待另一个线程的通知。
#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; }); // 等待通知
std::cout << "Worker is running!" << std::endl;
}
int main() {
std::thread t(worker);
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lock(mtx);
ready = true;
}
cv.notify_one(); // 通知线程
t.join();
return 0;
}
7. 线程间通信
使用 std::future
和 std::promise
std::promise
:允许线程间传递值。std::future
:用于获取异步结果。
#include <iostream>
#include <thread>
#include <future>
void compute(std::promise<int> p) {
p.set_value(42); // 设置结果
}
int main() {
std::promise<int> p;
std::future<int> f = p.get_future();
std::thread t(compute, std::move(p));
std::cout << "Result: " << f.get() << std::endl; // 获取结果
t.join();
return 0;
}
8. 总结
C++ 的线程功能强大,可以用于实现高效的多任务并行处理。然而,开发多线程程序需要注意以下几点:
- 数据同步:通过
std::mutex
或其他机制避免数据竞争。 - 死锁问题:小心使用多个锁,合理设计锁的顺序。
- 资源管理:使用智能指针和
std::lock_guard
等工具确保资源安全。
正确地使用线程可以极大地提升程序的性能,但也增加了程序的复杂性和调试难度。