0

I'm trying to read asynchronously from stdin using ASIO on windows.

To this end, I tried to use an asio::windows::object_handle.

I would expect that after async_waiting on the STDIN handle, ::ReadFile on the same handle should not block.

However, it seems that this is not the case. In the following program, I would expect echos of my input from the first coroutine, interlaced with the test n printouts from the second.

Instead, the ::ReadFile call is blocking the io_context.run(), so the test n prints only happen after I presss return in the console.

#include <sdkddkver.h>

#include <chrono>
#include <iostream>

#include "asio/asio.hpp"

int main() {
  using namespace std::chrono_literals;

  asio::io_context ctx;
  asio::high_resolution_timer timer(ctx);
  asio::windows::object_handle stdin_handle(ctx,
                                             ::GetStdHandle(STD_INPUT_HANDLE));

  /// stdin loop
  asio::co_spawn(
      ctx,
      [&]() -> asio::awaitable<void> {
        for (;;) {
          co_await stdin_handle.async_wait(asio::use_awaitable);
          char buf[100];
          DWORD n;

          //  this is blocking?
          ReadFile(stdin_handle.native_handle(), buf, sizeof(buf), &n, NULL);

          std::cout << "input (" << n << "): " << std::string_view(buf, n);
        }
      },
      asio::detached);

  /// stdout loop
  asio::co_spawn(
      ctx,
      [&]() -> asio::awaitable<void> {
        for (int i = 0; i < 10; i++) {
          std::cout << "test " << i << "\n";
          timer.expires_after(1s);
          co_await timer.async_wait(asio::use_awaitable);
        }
      },
      asio::detached);

  ctx.run();

  return 0;
}

What am I doing wrong? Does object_handle::async_wait wait for things other than actual input? How do I accomplish this?

MHebes
  • 2,290
  • 1
  • 16
  • 29
  • 1
    for asynchronous i/o handle need be created with asynchronous option. – RbMm Jun 01 '22 at 19:21
  • @RbMm which handle? How do I do that? – MHebes Jun 01 '22 at 19:29
  • A thought exercise.... How many bytes have to be ready on `stdin` for `async_wait` to complete? How many bytes does `ReadFile` need? – Ben Voigt Jun 01 '22 at 19:32
  • 1
    The handle returned by `GetStdHandle(STD_INPUT_HANDLE)` is unlikely to have been opened for asynchronous operations, since that would break functions like `getchar()`. – Raymond Chen Jun 01 '22 at 19:34
  • @BenVoigt any number. Just pressing return sometime after the timer’s expiry time will trigger the second corotinue’s resume. Also, if I change `sizeof(buf)` to 1, I get the same behavior (expect of course the echo is broken up into single chars). – MHebes Jun 01 '22 at 19:35
  • To answer "wait for things other than actual input", see https://learn.microsoft.com/en-us/windows/win32/sync/synchronization-objects and also https://learn.microsoft.com/en-us/windows/console/low-level-console-input-functions Note "The state of a console input handle becomes signaled when there are unread records in its input buffer" But "records" here includes everything `ReadConsoleInput` knows about, which is a whole lot more than `ReadFile` is looking for. – Ben Voigt Jun 01 '22 at 19:40
  • Of course if your `stdin` is redirected to a pipe or a file, then the console synchronization rules no longer apply, and instead the pipe or file rules do. – Ben Voigt Jun 01 '22 at 19:41
  • 2
    Your question is a duplicate of https://stackoverflow.com/q/19955617/103167 only you're not calling the Win32 API wait functions, you're having boost do it for you. – Ben Voigt Jun 01 '22 at 19:46
  • 1
    If you want async operations, just use the Asio [stream_handle](https://www.boost.org/doc/libs/1_79_0/doc/html/boost_asio/reference/windows__stream_handle.html) object. Note however that that may not support terminals (same on POSIX). It may(?) work if input is redirected from another type of stream – sehe Jun 01 '22 at 19:53
  • Thanks all for your input. stream_handle may work well for my needs. @BenVoigt thanks for the context about stdin as a file vs the console as an event emitter – MHebes Jun 03 '22 at 18:36

0 Answers0