C++ 异步编程 并发编程技术

embedded/2024/10/17 2:18:56/

C++ 异步编程是一种并发编程技术,用于通过非阻塞的方式执行任务。与传统的同步编程相比,异步编程可以提高程序的效率,尤其是在处理 I/O 操作、网络请求或多线程任务时,避免主线程等待任务完成。

1. 异步编程的基本概念

异步编程主要解决如何在不阻塞主线程的情况下,执行耗时的任务,并在任务完成时以某种方式通知或继续执行程序的其他部分。在 C++ 中,异步编程的主要机制包括:

多线程(Threading):通过多线程来实现并行执行任务。
异步任务(Asynchronous Task):通过 std::future 和 std::promise 等方式执行异步任务。
事件循环和回调(Event Loop & Callbacks):通过事件触发器在任务完成后执行相应的回调函数。
异步编程的主要目标是:

提高程序的响应性,尤其是 UI 程序或网络服务。
更好地利用系统资源,避免线程或 CPU 被阻塞在等待上。

2. C++ 中的异步编程工具

C++11 引入了大量支持异步编程的库和工具,使得 C++ 异步编程变得更加易用和标准化。以下是 C++ 异步编程的几种主要方式:

2.1. std::thread

std::thread 是 C++ 中用来创建和管理线程的基本工具。线程使得多个任务能够并发运行。

  • 创建线程:
#include <iostream>
#include <thread>void task(int n) {std::cout << "Task " << n << " is running in a separate thread.\n";
}int main() {std::thread t(task, 10);t.join();  // 等待线程 t 执行完成return 0;
}
  • 线程的生命周期:
join():等待线程执行完毕,阻塞主线程直到子线程结束。
detach():让线程在后台运行,主线程不等待其完成。
使用 std::thread 虽然可以实现简单的并发任务,但对于复杂的异步任务管理,需要更高层次的抽象,如 std::async。

2.2. std::async 和 std::future

std::async 是 C++11 提供的更高层的异步编程接口。它可以创建一个异步任务,并返回一个 std::future 对象来获取异步任务的结果。

  • 异步任务的执行:
#include <iostream>
#include <future>
#include <thread>int long_computation(int n) {std::this_thread::sleep_for(std::chrono::seconds(2));  // 模拟长时间计算return n * n;
}int main() {// 创建一个异步任务std::future<int> result = std::async(std::launch::async, long_computation, 10);// 执行其他任务std::cout << "Doing other things while waiting...\n";// 获取异步任务的结果int value = result.get();  // 这个操作会阻塞主线程直到结果准备好std::cout << "Result is " << value << "\n";return 0;
}
  • std::async 的模式:

std::launch::async:强制在新线程中异步执行。
std::launch::deferred:任务不会立即执行,只有调用 get() 或 wait() 时才会执行。
std::future 是 std::async 的返回类型,用于表示一个异步操作的结果。它提供以下几个重要的方法:

get():阻塞主线程直到任务完成并返回结果。
wait():阻塞主线程,直到任务完成,但不返回结果。
wait_for() 和 wait_until():允许设置等待超时,检查任务是否完成。

2.3. std::promise 和 std::future

std::promise 和 std::future 是 C++ 提供的另一组异步任务管理工具。std::promise 用于设置异步操作的结果,而 std::future 用于获取结果。

  • std::promise 和 std::future 的用法:
#include <iostream>
#include <thread>
#include <future>void calculate_square(std::promise<int>&& p, int n) {int result = n * n;std::this_thread::sleep_for(std::chrono::seconds(2));p.set_value(result);  // 设置结果
}int main() {std::promise<int> p;  // 创建 promise 对象std::future<int> result = p.get_future();  // 获取 future// 启动线程并将 promise 对象传递进去std::thread t(calculate_square, std::move(p), 10);// 主线程做其他事情std::cout << "Waiting for result...\n";// 获取结果(会阻塞主线程)int value = result.get();std::cout << "Result is " << value << "\n";t.join();return 0;
}

这种方式适用于更加复杂的异步任务场景,特别是当你需要手动控制任务的开始和结束时。

2.4. std::packaged_task

std::packaged_task 是 C++11 提供的一种将任务打包为可异步调用的工具。它可以与 std::future 一起使用,允许我们将函数、lambda 表达式等包装为异步任务。

  • std::packaged_task 示例:
#include <iostream>
#include <future>
#include <thread>int compute_sum(int a, int b) {return a + b;
}int main() {std::packaged_task<int(int, int)> task(compute_sum);  // 打包任务std::future<int> result = task.get_future();  // 获取 future 对象std::thread t(std::move(task), 5, 7);  // 启动线程,传入参数std::cout << "Result: " << result.get() << "\n";  // 获取结果t.join();return 0;
}

2.5. std::mutex、std::lock_guard 和 std::unique_lock

在异步编程或多线程编程中,保护共享资源免受并发访问是至关重要的。C++ 提供了 std::mutex(互斥量)来保护共享数据。std::lock_guard 和 std::unique_lock 提供了自动锁定和解锁的机制,避免手动管理锁的复杂性。

  • 使用 std::mutex 进行线程同步:
#include <iostream>
#include <thread>
#include <mutex>std::mutex mtx;  // 互斥量保护共享资源void print_message(const std::string& message) {std::lock_guard<std::mutex> lock(mtx);  // 自动加锁和解锁std::cout << message << std::endl;
}int main() {std::thread t1(print_message, "Hello from thread 1");std::thread t2(print_message, "Hello from thread 2");t1.join();t2.join();return 0;
}

std::unique_lock 的灵活性: std::unique_lock 比 std::lock_guard 更加灵活,支持延迟加锁、手动解锁等操作。

std::unique_lock<std::mutex> lock(mtx);
lock.unlock();  // 手动解锁
lock.lock();    // 手动加锁

3. C++ 异步编程的实际应用场景

C++ 的异步编程在以下几种场景中有着广泛的应用:

3.1. 高性能 I/O

异步 I/O 操作避免了主线程的阻塞,特别是在高并发的网络服务中,通过异步操作处理大量的请求可以显著提高吞吐量。

3.2. 并行计算

对于计算密集型任务,使用多线程或异步任务将计算拆分为多个并发执行的任务,能够更有效地利用多核 CPU 提升性能。

3.3. 事件驱动编程

在 GUI 或服务器编程中,异步编程能够避免用户界面或服务器的主线程被阻塞,从而保持系统的响应性。

4. 总结

C++ 提供了多种异步编程工具,从基本的 std::thread 到更高级的 std::async 和 std::future。异步编程可以显著提高程序的效率,特别是在 I/O 密集型和计算密集型任务中。熟悉这些工具的使用,能够帮助开发者编写出更高效、响应更快的程序。


http://www.ppmy.cn/embedded/126408.html

相关文章

IDE启动失败

报错&#xff1a;Cannot connect to already running IDE instance. Exception: Process 24,264 is still running 翻译&#xff1a;无法连接到已运行的IDE实例。异常:进程24,264仍在运行 打开任务管理器&#xff0c;找到PID为24264的CPU线程&#xff0c;强行结束即可。 【Ct…

[spring]spring事务和事务传播机制

文章目录 一. 事务Spring中的事务实现编程式事务声明式事务TransactionalTransactional作用 Transactional详解1. rollbackFor2. 事务隔离级别mysql事务隔离级别Spring事务隔离级别 3. 事务传播机制什么是事务传播机制事务传播机制有哪些Spring事务传播机制使用REQUIRED(加入事…

conda打包

tar 是一个在 Unix 和类 Unix 系统中常用的命令行工具&#xff0c;用于打包多个文件和目录到一个归档文件&#xff08;通常称为 tarball&#xff09;&#xff0c;以及从这些归档文件中解包文件和目录。 以下是使用 tar 进行打包和解包的基本用法&#xff1a; 打包&#xff08;…

docker overlay 占用空间太大,迁移到 /data/

将 Docker 的 overlay 存储驱动迁移到 /data/ 目录下&#xff0c;可以通过以下步骤完成&#xff1a; 1. 停止 Docker 服务 首先&#xff0c;停止 Docker 服务以确保没有容器在运行&#xff0c;并且数据不会被写入到当前的存储位置。 sudo systemctl stop docker2. 备份现有数…

微信小程序处理交易投诉管理,支持多小程序,一键授权模式

大家好&#xff0c;我是小悟 1、问题背景 玩过微信小程序生态的&#xff0c;或许就有这种感受&#xff0c;如果收到投诉单&#xff0c;不会及时通知到手机端&#xff0c;而是每天早上10:00向小程序的管理员及运营者推送通知。通知内容为截至前一天24时该小程序账号内待处理的交…

中信银行信息技术管理部各岗位社会招聘要求

科技人力资源支持岗 职位描述 1.结合科技人才发展规划,组织人才梯队建设,对人员任用、评价、培养等进行评估并提出建议、解决方案; 2.优化信息科技关键岗位及关键人才的管理体系,包括关键岗位识别、岗位能力梳理、人才盘点及评估等工作; 3.搭建信息科技文化体系,并推动金…

C++ STL容器(五) —— priority_queue 底层剖析

这篇来讲下 priority_queue&#xff0c;其属于 STL 的容器适配器&#xff0c;容器适配器是在已有容器的基础上修改活泼限制某些数据接口以适应更特定的需求&#xff0c;比如 stack 栈使数据满足后进先出&#xff0c;queue 队列使数据满足先进先出&#xff0c;其都是在已有容器上…

Kafka相关知识

Kafka保证消息的可靠投递&#xff1f; Kafka 确保消息可靠投递的机制主要包括以下几点&#xff1a; 消息确认机制&#xff08;ACKs&#xff09;&#xff1a;Kafka 提供了三种级别的消息确认机制&#xff0c;以确保生产者发送的消息能够可靠地被 Broker 接收。 acks0&#xff…