C++11 引入了 <thread>
头文件,为多线程编程提供了直接的支持。利用 <thread>
,程序员可以在程序中创建和管理线程,实现并发执行,充分利用多核处理器的优势。本文介绍了 <thread>
的基本用法、线程创建与管理、以及常见的注意事项。
目录
<thread>
头文件简介- 线程的创建与启动
- 线程的管理
- 3.1 线程加入与分离
- 线程安全与同步
- 4.1 互斥量(mutex)
- 4.2 锁(lock)
- 常见注意事项
- 结论
1. <thread>
头文件简介
<thread>
是 C++ 标准库中用于多线程编程的头文件,提供了 std::thread
类,用于创建和管理线程。借助 <thread>
,可以启动独立执行的函数或可调用对象,使得程序能够并发运行多个任务。
要使用多线程功能,只需包含头文件:
#include <thread>
2. 线程的创建与启动
2.1 基本线程创建
可以通过 std::thread
创建一个线程,并将一个函数传递给它,使该函数在新线程中执行。
示例:
#include <iostream>
#include <thread>
void threadFunction() {
std::cout << "Hello from thread!" << std::endl;
}
int main() {
// 创建一个线程,执行 threadFunction
std::thread t(threadFunction);
// 主线程等待子线程执行完毕
t.join();
std::cout << "Thread finished." << std::endl;
return 0;
}
在上述代码中,线程 t
启动后会调用 threadFunction()
。调用 t.join()
可等待子线程执行完毕,再继续主线程的执行。
2.2 传递参数给线程
可以在创建线程时向可调用对象传递参数。参数会被拷贝(或移动)传递到新线程中。
示例:
#include <iostream>
#include <thread>
void printMessage(const std::string &message, int count) {
for (int i = 0; i < count; ++i) {
std::cout << message << std::endl;
}
}
int main() {
// 向线程传递参数
std::thread t(printMessage, "Hello, C++ multithreading!", 3);
t.join();
return 0;
}
在此示例中,字符串和整数参数被传递给线程函数 printMessage
,线程会输出指定次数的消息。
3. 线程的管理
3.1 线程加入与分离
- 加入(join): 调用
join()
后,主线程等待子线程结束再继续执行,确保线程之间的同步。 - 分离(detach): 调用
detach()
后,线程在后台独立运行,与主线程分离。需要确保被分离线程在其生命周期内不会访问已销毁的资源。
示例:
#include <iostream>
#include <thread>
#include <chrono>
void backgroundTask() {
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "Background task completed." << std::endl;
}
int main() {
std::thread t(backgroundTask);
// 使用 detach() 分离线程,线程在后台运行
t.detach();
// 主线程继续执行其他任务
std::cout << "Main thread is doing other work." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(3));
std::cout << "Main thread finished." << std::endl;
return 0;
}
调用 detach()
后,线程 t
将不再受主线程控制。注意:分离线程后要确保它所依赖的资源在其运行期间有效。
4. 线程安全与同步
多线程环境下,多个线程同时访问共享资源时可能会发生竞态条件。为确保线程安全,常用互斥量(mutex)和锁(lock)。
4.1 互斥量(mutex)
std::mutex
用于保护共享数据,防止同时访问引发数据竞争。
示例:
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
int counter = 0;
void increment() {
// 锁住互斥量,保护共享数据
std::lock_guard<std::mutex> lock(mtx);
++counter;
std::cout << "Counter: " << counter << std::endl;
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
return 0;
}
在上述代码中,std::lock_guard
自动管理互斥量的加锁和解锁,确保多个线程安全地更新 counter
。
4.2 锁(lock)
除了 std::lock_guard
,还可以使用 std::unique_lock
来获得更灵活的锁管理功能,如延时加锁或条件变量协作。
5. 常见注意事项
- 资源管理: 避免线程在退出前访问已销毁的资源。对于分离线程,需要确保其运行期间所需资源保持有效。
- 异常处理: 在线程函数中捕获异常,防止未捕获异常导致程序崩溃。
- 避免死锁: 多个互斥量同时使用时,应遵循一致的加锁顺序,避免死锁的发生。
- 合理调度: 利用
std::this_thread::yield()
或sleep_for
进行适当的调度,让线程更公平地共享 CPU 时间。
6. 结论
C++ <thread>
提供了创建、管理和同步线程的基础设施,使得编写并发程序变得更简单和安全。通过掌握线程的基本用法、正确使用互斥量和锁等同步机制,你可以构建高效且线程安全的多线程应用程序。掌握 <thread>
是现代 C++ 编程的重要技能之一。
推荐阅读:
发表回复