Proactor 模式
Proactor 模式是一种异步 I/O 处理模式,常用于高性能网络服务器和并发系统中。与传统的 Reactor 模式(基于事件驱动的 I/O 多路复用)不同,Proactor 模式使用异步 I/O 操作来处理 I/O 任务,从而提高了系统的并发能力和响应速度。
1)异步
优点:异步编程有助于提高应用程序的响应性和性能,特别是在涉及大量I/O操作或网络请求的应用场景下。常见的异步编程技术包括回调函数、事件循环、Promise(在JavaScript中)、协程(如Python的asyncio)等。这些技术可以帮助开发者构建高效、非阻塞的系统。
异步示例:
程序执行到“读取文件”操作,并启动该操作。
程序不会等待文件读取完成,而是继续执行后面的指令。
当文件读取完成后,通过回调函数、事件通知或其他机制来处理读取的结果。
2)使用回调函数的异步例子
#include <iostream>
#include <thread>
#include <functional>
// 模拟一个耗时的任务
void simulateLongRunningTask(std::function<void(int)> callback)
{
std::this_thread::sleep_for(std::chrono::seconds(3)); // 模拟3秒延时
int result = 42; // 模拟任务结果
callback(result); // 完成时调用回调函数
}
int main()
{
// 创建一个lambda函数作为回调
auto callback = [](int result) {
std::cout << "异步操作完成,结果为: " << result << std::endl;
};
// 启动一个新线程来执行异步任务
std::thread worker(simulateLongRunningTask, callback);
// 主线程继续执行其他任务
std::cout << "主线程继续工作..." << std::endl;
// 等待异步任务线程结束
worker.join();
return 0;
}
在这个例子中,simulateLongRunningTask函数模拟了一个耗时较长的任务,并在任务完成后调用了传递给它的回调函数callback。主函数main创建了一个新的线程来执行这个任务,并且在新线程中执行任务的同时,主线程能够继续执行其他任务。worker.join()用于等待新线程完成其任务。
3)一个简单echo异步服务器引出的问题
“Echo”模式通常指的是一个简单的通信模式,其中服务器接收来自客户端的数据,并将其原样返回给客户端。这种模式经常用于测试网络连接和协议栈的正确性,也可以作为教学示例来演示基本的网络编程概念。
a)问题1:当服务器收到数据将要应答时客户端断开,此时
调用 async_write 触发发送回调:
即使客户端已经断开连接,服务器仍然会尝试调用 async_write 发送数据。由于客户端已经断开,async_write 的回调函数会被触发,并且错误码 ec 会是非零值。
调用析构函数析构session
客户端关闭后触发读就绪事件:
客户端断开连接后,在 TCP 层面上,服务器会收到一个读就绪事件。这是因为 TCP 协议在连接关闭时会发送 FIN 包,这可能会导致服务器误以为有数据可读。
在读回调函数中,再次触发析构函数
现象:出现两次析构
解决方法:将session智能指针存到map中,此时智能指针会自动析构,再在读写出错时调用clean清除map中uuid
b)问题2:重复之前的步骤,在服务器会先触发写回调函数的错误处理,再触发读回调函数的错误处理,这样session就会两次从map中移除,因为map中key唯一,所以第二次map判断没有session的key就不做移除操作了。
但是这么做程序会奔溃;
原因:写和读操作中,回调函数会两次调用session的内存,第一次调用时session的内存已经被析构(从map中移除时自动析构),第二次访问内存时奔溃
解决办法:
将session生命周期与回调函数绑定
此时需要在第一次绑定读写回调函数的时候传入智能指针的值
需要从一个对象内部获取一个指向自身的指针。如果这个对象是由 std::shared_ptr 管理的,那么直接返回 this 指针是不够的,因为 this 指针是一个裸指针,它无法提供对象的生命周期管理信息。
std::enable_shared_from_this 提供了一种方法,使得可以从对象内部返回一个 std::shared_ptr,从而在保证对象生命周期的同时,也能够安全地访问对象。
通过shared_from_this()函数返回智能指针,使用这个函数需要继承类std::enable_shared_from_this
void CSession::Start(){
memset(_data, 0, MAX_LENGTH);
_socket.async_read_some(boost::asio::buffer(_data, MAX_LENGTH), std::bind(&CSession::HandleRead, this,
std::placeholders::_1, std::placeholders::_2, shared_from_this()));
}
4)asio线程池
从 Boost 1.72 版本开始,Boost.Asio 引入了 boost::asio::thread_pool 类,这是一个专门用于管理线程池的类,简化了线程池的创建和管理。