使用C++ boost从零构建一个异步文件IO系统

前言

  • 因为本科毕业设计中要做一个分布式文件系统,其中一个模块需要实现文件IO。为了验证我对异步IO的理解,决定造一个异步文件IO的轮子。操作系统已经给出各种异步操作的API,如重叠IO, IOCP,kqueue,select,poll,epoll等机制,而且C++也有很多跨平台的异步IO库,如libevent,boost::asio等。我参考已有的实现来完善这个小系统的功能。
  • 渣技术,渣代码,该日志也只是作为这个工程的记录,出现问题请各位指出。

概述

  • 同步与异步:

  同步:假如我想对一个文件(socket也同理)进行处理,那么一般的流程就是:

  

1 fstream file;
2 file.open();
3 file.read();
4 //do something
5 file.close();

  通常情况下,当这个线程运行到read()时会被阻塞,直到文件读取完成。

  异步:

  还是上面的代码,我在read()时通过操作系统或库提供的异步机制,告诉操作系统我想读一个文件,数据读完后执行某个功能;而当前线程在交代完操作系统该做什么工作之后,还可以做些别的事情(线程不必等待文件IO完成)。

  • 线程池

  为了避免IO阻塞线程导致程序无响应,完全可以为每一个文件操作创建一个线程,这样就可以同时处理多个文件了。但是创建线程,切换线程,销毁线程也是一笔资源开销,如果想重复使用已有的线程,就可以使用线程池。作为线程池,至少要提供创建线程和提交任务的功能,复杂一点可以智能控制线程池里的线程数量,还应该具有基本的负载均衡功能。这个文件系统中就会使用线程池。Windows API中的ThreadPool就很好用,但既然是造轮子,那么为了造轮子而造轮子也没什么关系,干脆就写个简单的线程池出来。

  • 使用的库

  这个模块只使用stl 和boost 两个库。

  stl主要涉及容器和fstream。boost涉及到智能指针shared_ptr,线程同步shared_mutex,lock_guard, boost::filesystem中的path和一些文件操作,线程操作创建退出等。

  •  智能指针

  自古以来内存管理都是C/C++中的重头戏,智能指针的功能就是分配出来的内存由库管理,如果某个智能指针指向的内存,通过其他的智能指针也能访问到(即有多个引用),那么该智能指针即时被销毁,指向的内存也不会销毁;只有这块内存没有引用,才会被库释放。

  • boost::filesystem

  这个库提供了一些跨平台文件操作的API,如文件夹遍历,查看属性,删除文件等。path类可以记录跨平台的路径。

  • 因为水平有限,这个模块基本不会出现跟模板有关的实现。(以后再说)

实现

  AsyncStatus是异步IO中需要实现的功能。像读,写,放弃异步操作,错误处理等。

  ErrorCode会出现在回调函数中,表示之前异步读写的结果,如正在处理,出错,EOF等。

  FS_Handle_ST:这个结构体对应一个文件路径。在系统中每个handle都是唯一的,系统有一个map,通过handle可以找到它对应的路径。

  FS_AsyncHandle_ST:标识某个handle需要执行的任务,每个AsyncHandle都需要指定status即任务。一个handle可以有多个异步任务,但多个任务在系统中按照队列顺序执行。

 1     enum QueueOperation { PUSH_BACK, PUSH_FRONT };
 2     enum AsyncStatus { NONE, APPEND_WRITE, WRITE, READ, READ_ALL, ABORT, ERROR, EXIT };
 3     enum ErrorCode { DONE, PENDING, END_OF_FILE, OPEN_FAIL, BAD_STREAM, IO_FAIL, UNKNOWN_ERROR };        
 4 
 5     typedef uintmax_t FS_Handle;
 6     typedef uintmax_t FS_AsyncHandle;
 7 
 8     struct FS_AsyncHandle_ST {
 9         FS_Handle fileHandle = 0;
10         FS_AsyncHandle asyncHandle = 0;
11         AsyncStatus status = AsyncStatus::NONE;
12     };
13 
14     struct FS_Handle_ST {
15         FS_Handle handle = 0;
16         boost::filesystem::path fullPath;
17     };        

  回调函数:异步操作完成之后要做什么。使用的时候把功能在派生类里实现,重载虚函数run就可以了。

 1     class FileSystemIOCallback {
 2     public:
 3         void operator=(const FileSystemIOCallback & cb) {
 4             //..
 5         }
 6 
 7         FileSystemIOCallback(const FileSystemIOCallback & cb) {
 8             //..
 9         }
10 
11         FileSystemIOCallback() {
12             //...
13         }
14 
15         virtual ~FileSystemIOCallback() {
16 
17         }
18 
19         virtual void run(const FS_AsyncHandle_ST & ast, ErrorCode e, void * data, uintmax_t count) {
20             //...
21         }
22     };
  •  功能概述

  fstream中有一个非常有趣的函数,readsome()方法,这个方法提出的目的是尽可能减少同步读取的阻塞时间。该方法会读取fstream内部缓冲区里的数据,读取的字节数取决于fstream内部缓冲区和作为参数传递给它的缓冲区的大小。举个例子,如果fstream缓冲区里只有10字节,我参数给出的缓冲区大小为100字节,不管这个文件后面还有没有数据,它只会去读10个字节。操作系统和函数库可能会使用由硬件引发的中断来读取数据,运行原理类似,但其具体实现未知,还要进一步了解。

  既然IO操作要阻塞线程很长一段时间,那么就把IO操作扔给线程或纤程,主线程只负责提交任务。

--- 未完待续

转载于:https://www.cnblogs.com/nemooo/p/6719281.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的 C++ Crow Asio 应用程序示例,它基于异步 IO,并使用 Boost 库进行编译: ```c++ #include "crow_all.h" #include <boost/asio.hpp> #include <memory> int main() { // 创建一个 io_context 对象 auto io = std::make_shared<boost::asio::io_context>(); // 创建一个 Crow 应用程序对象,并将 io_context 对象传递给它 crow::SimpleApp app; CROW_ROUTE(app, "/")([](){ return "Hello, World!"; }); // 创建一个 TCP 服务器对象,并将应用程序对象和 io_context 对象传递给它 boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 8080); boost::asio::ip::tcp::acceptor acceptor(*io, endpoint); acceptor.listen(); // 开始监听客户端请求,并启动 io_context 对象的事件循环 boost::asio::spawn(acceptor.get_executor(), [&](boost::asio::yield_context yield){ while(true){ boost::system::error_code ec; boost::asio::ip::tcp::socket socket(*io); acceptor.async_accept(socket, yield[ec]); if(!ec){ boost::asio::spawn(socket.get_executor(), [&](boost::asio::yield_context yield){ try{ // 处理客户端请求 auto conn = std::make_shared<crow::Connection>(app, std::move(socket)); conn->start(); }catch(const std::exception& e){ std::cerr << "Exception in connection: " << e.what() << std::endl; } }); } } }); // 启动应用程序的主循环 app.port(8080).run(); // 启动 io_context 对象的事件循环 io->run(); return 0; } ``` 这个程序创建了一个简单的 Crow 应用程序,监听 8080 端口,并在客户端请求时返回 "Hello, World!"。其中 `boost::asio::spawn()` 方法用于在异步 IO 模式下处理客户端请求,同时启动了 `io_context` 对象的事件循环。在程序运行时,需要在终端中使用编译器和 Boost 库进行编译,并执行编译后的可执行文件

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值