在现代c++++并发编程中,std::thread和std::async是主要工具,其中std::thread用于底层线程管理,而std::async提供更高层次的异步任务封装。1. std::thread需要手动处理线程生命周期(join或detach)及数据同步;2. std::async配合std::future简化异步编程,自动处理线程管理和异常传递;3. 使用std::launch::async可确保任务在独立线程执行,避免延迟模式带来的串行化问题;4. 线程同步需借助互斥量(std::mutex)和条件变量(std::condition_variable)来保障数据安全与线程协作;5. 推荐优先使用std::async以减少复杂性,除非需要对线程进行细粒度控制。

现代C++中,使用线程库进行并发编程,主要围绕
std::thread
std::async
std::thread
join
detach
std::async
std::future

在C++11及更高版本中,
std::thread
std::async
使用 std::thread
std::thread
立即学习“C++免费学习笔记(深入)”;

#include <iostream>
#include <thread>
#include <vector>
#include <numeric> // For std::iota
void do_work(int id) {
std::cout << "Thread " << id << " is working...\n";
// 模拟一些计算
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "Thread " << id << " finished.\n";
}
int main() {
std::cout << "Main thread starts.\n";
std::thread t1(do_work, 1); // 创建并启动线程t1
// 也可以使用lambda表达式
std::thread t2([](int data) {
std::cout << "Lambda thread processing data: " << data << "\n";
}, 42);
// 线程的生命周期管理至关重要
// 必须在线程对象销毁前调用 join() 或 detach()
t1.join(); // 等待t1完成
t2.join(); // 等待t2完成
std::cout << "All threads joined. Main thread ends.\n";
return 0;
}这里有个小细节,如果你不
join()
detach()
std::thread
join()
detach()
使用 std::async
std::future
std::async
std::future
future

#include <iostream>
#include <future> // For std::async and std::future
#include <chrono> // For std::chrono::milliseconds
int calculate_sum(int a, int b) {
std::cout << "Calculating sum of " << a << " and " << b << "...\n";
std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟耗时操作
return a + b;
}
int main() {
std::cout << "Main thread launching async task.\n";
// 启动一个异步任务,并获取其future
// std::launch::async 强制在新线程中运行
// std::launch::deferred 延迟到 future 的 get() 或 wait() 时才运行
// 默认是 std::launch::async | std::launch::deferred,由系统决定
std::future<int> result_future = std::async(std::launch::async, calculate_sum, 10, 20);
std::cout << "Main thread continues its work...\n";
// 可以在这里做其他事情,不必等待
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Main thread waiting for async result...\n";
try {
int sum = result_future.get(); // 获取结果,会阻塞直到任务完成
std::cout << "Async task result: " << sum << "\n";
} catch (const std::exception& e) {
std::cerr << "An error occurred: " << e.what() << "\n";
}
std::cout << "Main thread ends.\n";
return 0;
}std::async
get()
谈到
std::thread
std::thread
join
detach
std::terminate
创建
std::thread
#include <iostream>
#include <thread>
#include <string>
#include <chrono>
void simple_func(int count, const std::string& msg) {
for (int i = 0; i < count; ++i) {
std::cout << "Thread (func): " << msg << " - " << i << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
}
struct MyFunctor {
void operator()(double value) {
std::cout << "Thread (functor): Processing value " << value << std::endl;
}
};
class Worker {
public:
void do_something(const std::string& task_name) {
std::cout << "Thread (member): " << task_name << " is active." << std::endl;
}
};
int main() {
// 1. 使用普通函数
std::thread t1(simple_func, 3, "Hello from t1");
// 2. 使用lambda表达式
std::thread t2([](int id) {
std::cout << "Thread (lambda): ID " << id << " says hi!" << std::endl;
}, 101);
// 3. 使用函数对象
MyFunctor mf;
std::thread t3(mf, 3.14); // 注意:mf会被拷贝到线程内部
// 4. 使用类的成员函数 (需要传递对象实例的指针或引用)
Worker worker_obj;
std::thread t4(&Worker::do_something, &worker_obj, "Complex Task");
// 关键:管理线程生命周期
// join():等待线程完成。这是最常见的用法,确保子线程的工作在主线程继续前完成。
t1.join();
t2.join();
t3.join();
t4.join(); // 必须等待所有线程,否则程序可能在它们完成前结束
std::cout << "All threads have finished their work." << std::endl;
// 另一个选择是 detach()
// std::thread detached_t([](){
// std::cout << "I'm a detached thread, running independently!\n";
// std::this_thread::sleep_for(std::chrono::seconds(1));
// std::cout << "Detached thread finished.\n";
// });
// detached_t.detach(); // 一旦detach,你将无法再控制这个线程,也无法join它
// 注意:如果一个线程被detach,主程序退出时,如果它还在运行,可能会被操作系统强制终止,
// 或者继续运行直到完成,具体行为取决于操作系统。
// 一般来说,除非你明确知道自己在做什么,否则优先使用 join()。
return 0;
}参数传递时,要注意引用传递。如果你想在线程函数中修改主线程的变量,需要使用
std::ref
#include <iostream>
#include <thread>
#include <functional> // For std::ref
void increment_by_ref(int& counter) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
counter++;
std::cout << "Thread: counter is now " << counter << std::endl;
}
int main() {
int my_counter = 0;
// 错误:默认是值拷贝,线程内部修改的是拷贝
// std::thread t1(increment_by_ref, my_counter);
// 正确:使用std::ref进行引用传递
std::thread t1(increment_by_ref, std::ref(my_counter));
t1.join();
std::cout << "Main: final counter is " << my_counter << std::endl; // 应该显示 1
return 0;
}掌握
join()
detach()
std::thread
join()
detach()
std::async
std::future
join
detach
它的核心思想是:你提交一个任务(可调用对象),
std::async
std::future
future
future.get()
get()
#include <iostream>
#include <future>
#include <chrono>
#include <stdexcept> // For std::runtime_error
double divide(double numerator, double denominator) {
std::cout << "Async task: Performing division...\n";
std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟计算耗时
if (denominator == 0) {
throw std::runtime_error("Division by zero!");
}
return numerator / denominator;
}
int main() {
std::cout << "Main: Launching division tasks.\n";
// 正常情况:异步执行并获取结果
std::future<double> f1 = std::async(divide, 10.0, 2.0);
// 异常情况:异步执行,但会抛出异常
std::future<double> f2 = std::async(divide, 10.0, 0.0);
std::cout << "Main: Doing other stuff while tasks run...\n";
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// 获取第一个任务的结果
try {
double result1 = f1.get(); // 阻塞直到f1完成
std::cout << "Main: Result of 10.0 / 2.0 is: " << result1 << std::endl;
} catch (const std::exception& e) {
std::cerr << "Main: Error in f1: " << e.what() << std::endl;
}
// 获取第二个任务的结果
try {
double result2 = f2.get(); // 阻塞直到f2完成,并重新抛出异常
std::cout << "Main: Result of 10.0 / 0.0 is: " << result2 << std::endl;
} catch (const std::exception& e) {
std::cerr << "Main: Error in f2: " << e.what() << std::endl;
}
std::cout << "Main: All tasks processed.\n";
return 0;
}这里有个非常重要的点,就是
std::async
std::launch
std::launch::async
std::launch::deferred
future
get()
wait()
std::launch
std::launch::async | std::launch::deferred
这个默认行为有时候会让人困惑。我曾经就遇到过,写了一个
std::async
get()
std::launch::async
std::future
get()
wait()
std::future_status
wait_for
wait_until
总的来说,
std::async
一旦你开始在多个线程间共享数据,那么恭喜你,你已经踏入了并发编程最容易出错的雷区:数据竞争(Data Race)。没有适当的同步机制,多个线程同时读写同一个数据,其结果是不可预测的,这也就是所谓的未定义行为。为了避免这种混乱,我们需要互斥量(
std::mutex
std::condition_variable
互斥量(std::mutex
std::mutex
mutex
mutex
mutex
然而,直接使用
std::mutex::lock()
std::mutex::unlock()
std::lock_guard
std::unique_lock
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
#include <numeric> // For std::iota
std::mutex mtx; // 全局互斥量,保护 shared_data
int shared_data = 0;
void increment_shared_data(int id) {
for (int i = 0; i < 1000; ++i) {
// 使用 std::lock_guard 确保互斥访问
// 当 lock_guard 对象超出作用域时,会自动解锁
std::lock_guard<std::mutex> lock(mtx);
shared_data++;
// std::cout << "Thread " << id << ": shared_data = " << shared_data << std::endl; // 频繁输出会影响性能
}
}
int main() {
std::vector<std::thread> threads;
for (int i = 0; i < 10; ++i) {
threads.emplace_back(increment_shared_data, i);
}
for (auto& t : threads) {
t.join();
}
// 理论上,shared_data 应该是 10 * 1000 = 10000
std::cout << "Final shared_data: " << shared_data << std::endl; // 应该接近10000,如果没锁,会远小于
return 0;
}如果没有
std::lock_guard<std::mutex> lock(mtx);
shared_data
std::lock_guard
std::unique_lock
条件变量(std::condition_variable
std::condition_variable
std::mutex
wait()
notify_one()
notify_all()
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue> // 模拟生产者-消费者队列
std::mutex mtx_cv;
std::condition_variable cv;
std::queue<int> data_queue;
bool producer_finished = false; // 生产者是否已完成所有生产
void producer() {
for (int i = 0; i < 5; ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟生产时间
{
std::lock_guard<std::mutex> lock(mtx_cv);
data_queue.push(i);
std::cout << "Producer: Produced " << i << std::endl;
} // 锁在这里释放
cv.notify_one(); // 通知一个等待的消费者
}
{
std::lock_guard<std::mutex> lock(mtx_cv);
producer_finished = true;
}
cv.notify_all(); // 生产完成后,通知所有可能还在等待的消费者
}
void consumer(int id) {
while (true) {
std::unique_lock<std::mutex> lock(mtx_cv); // unique_lock 允许在 wait 期间释放锁
// 等待条件:队列不为空 或者 生产者已完成
cv.wait(lock, [&]{ return !data_queue.empty() || producer_finished; });
if (data_queue.empty() && producer_finished) {
std::cout << "Consumer " << id << ": Producer finished and queue is empty. Exiting.\n";
break; // 退出循环
}
int data = data_queue.front();
data_queue.pop();
std::cout << "Consumer " << id << ": Consumed " << data << std::endl;
// 锁在这里自动释放,或者手动释放 lock.unlock();
}
}
int main() {
std::thread prod_t(producer);
std::thread cons1_t(consumer, 1);
std::thread cons2_t(consumer, 2);
prod_t.join();
cons1_t.join();
cons2_t.join();
std::cout << "Main: All threads finished.\n";
return 0;
}条件变量的
wait()
wait()
除了`std::mutex
以上就是现代C++的线程库怎么使用 std thread与异步任务管理的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号