asio icon indicating copy to clipboard operation
asio copied to clipboard

asio::stream_file on windows

Open jQill opened this issue 2 years ago • 1 comments

#include <asio.hpp>
#include <iostream>

int main(int argc, char* argv[])
{
    asio::io_context context;
    asio::executor_work_guard<asio::io_context::executor_type> guard =
        asio::make_work_guard(context);
    asio::stream_file file(context, "D:/file.txt",
                           asio::stream_file::write_only | asio::stream_file::create);

    std::vector<char> s1(10, 'a');
    std::vector<char> s2(10, 'b');
    std::vector<char> s3(10, 'c');

    std::array<asio::const_buffer, 3> buffers;
    buffers[0] = asio::buffer(s1);
    buffers[1] = asio::buffer(s2);
    buffers[2] = asio::buffer(s3);

    asio::async_write(file, buffers,
                      [&](const asio::error_code& error, std::size_t length)
                      {
                          if (error)
                          {
                              std::cerr << "An error occurred: " << error.message() << '\n';
                          }
                          file.close();
                          context.stop();
                      });

    context.run();

    return 0;
}

Linux: aaaaaaaaaabbbbbbbbbbcccccccccc Windows: aaaaaaaaaa bbbbbbbbbb cccccccccc

jQill avatar Aug 25 '23 12:08 jQill

The problem is in how file_stream keeps track of the current position. All win_iocp_file_service async/non-async and read/write functions have the problem. It's easiest to see in write_some

  template <typename ConstBufferSequence>
  size_t write_some(implementation_type& impl,
      const ConstBufferSequence& buffers, asio::error_code& ec)
  {
    uint64_t offset = impl.offset_;
    impl.offset_ += asio::buffer_size(buffers);
    return handle_service_.write_some_at(impl, offset, buffers, ec);
  }

Where the impl.offset_ is incremented by asio::buffer_size(buffers) instead of the amount of bytes actually written by the function below it.

The solution is trivial for the non-async functions, but I don't know Asio's internals well enough to know how lifetimes of objects, like the impl one, are handled after async operation is finished. Especially seeing that Asio is not using smart pointers internally.

Perhaps someone here might have ideas/hints?

inetic avatar Apr 09 '25 14:04 inetic