Stack Exchange
Reading output of blocking process
I have some simple application:
//first.exe

int main()
{
  std::cout << "1" << std::endl;
  std::cout << "2" << std::endl;
  std::cout << "3" << std::endl;

  std::cin.get();

  return 0;
}

And I want to invoke a callback in separate application when "2" occurs in  stdout of application run as a child process:
//second.exe

int main()
{
  boost::asio::io_context context;
  boost::process::async_pipe out(context);
  boost::asio::streambuf buffer;

  boost::process::child("first.exe", boost::process::std_out > out);

  boost::asio::async_read_until(out, buffer, "2", [](boost::system::error_code code, std::size_t size)
  {
    //do something
  });

  context.run();

  return 0;
}

The problem is that I have to press any button in parent process due to std::cin.get() in child process to make io_context execute callback function. Do you have any suggestions to make it work as intended?

Use a pipe for standard input as well, and only write a single newline to that pipe?

In this case I don't think you need to do a thing (the std::cin read might just fail):
Live On Coliru
#include <boost/process.hpp>
#include <boost/asio.hpp>
#include <boost/process/async.hpp>
#include <iostream>
#include <iomanip>

int main()
{
    namespace bp = boost::process;
    boost::asio::io_context context;
    bp::async_pipe out(context);

    bp::child c("./first.exe", bp::std_out > out);

    boost::asio::streambuf buffer;
    boost::asio::async_read_until(out, buffer, "2", [&](boost::system::error_code code, std::size_t size) {
        if (code) {
            std::cerr << "Oops: " << code.message() << std::endl;
        } else {
            std::cerr << "received: " << size << " bytes: ";

            auto b = buffers_begin(buffer.data()), m = b+size, e = buffers_end(buffer.data());

            std::clog << std::quoted(std::string(b, m)) << std::endl;
            std::clog << "Note that we read more bytes: " << std::quoted(std::string(m, e)) << std::endl;

            buffer.consume(size);
        }
    });

    context.run();
    return c.exit_code();
}

Prints
received: 3 bytes: "1
2"
Note that we read more bytes: "
3
"

Cleaner
For cleanness, you could simply close std_in:
bp::child c("./first.exe", bp::std_out > out, bp::std_in.close());

And to be proper, also add the context for async io:
bp::child c("./first.exe", bp::std_out > out, bp::std_in.close(), context);

Those all work (see live).
More complicated
What if you actually need to supply input to get output? Or you need to supply input based on the output? Then the commenter is right: attach a pipe to std_in (or have a buffer be written asynchronously).
Sending a Fixed Buffer
Live On Coliru

first.cpp
#include <iostream>
int main() {
    using namespace std;
    string s;
    while (cin >> s)
        cout << "reversed: " << string(s.rbegin(), s.rend()) << endl;
}

main.cpp
#include <boost/process.hpp>
#include <boost/asio.hpp>
#include <boost/process/async.hpp>
#include <iostream>
#include <iomanip>

int main() {
    namespace bp = boost::process;
    boost::asio::io_context context;
    bp::async_pipe out(context);

    std::string i = "hello\nwo2rld\n";
    bp::child c("./first.exe", bp::std_out > out, bp::std_in < boost::asio::buffer(i), context);

    boost::asio::streambuf buffer;
    boost::asio::async_read_until(out, buffer, "2", [&](boost::system::error_code code, std::size_t size) {
        if (code) {
            std::cerr << "Oops: " << code.message() << std::endl;
        } else {
            std::cerr << "received: " << size << " bytes: ";

            auto b = buffers_begin(buffer.data()), m = b+size, e = buffers_end(buffer.data());

            std::clog << std::quoted(std::string(b, m)) << std::endl;
            std::clog << "Note that we read more bytes: " << std::quoted(std::string(m, e)) << std::endl;

            buffer.consume(size);
        }
    });

    context.run();
    return c.exit_code();
}


Prints
received: 30 bytes: "reversed: olleh
reversed: dlr2"
Note that we read more bytes: "ow
"

Sending Dynamic Data
Both synchronously and asynchronously:
#include <boost/process.hpp>
#include <boost/asio.hpp>
#include <boost/process/async.hpp>
#include <iostream>
#include <iomanip>

int main() {
    namespace bp = boost::process;
    boost::asio::io_context context;
    bp::async_pipe out(context), in(context);

    bp::child c("./first.exe", bp::std_out > out, bp::std_in < in, context);

    boost::asio::write(in, boost::asio::buffer("hello ", 6));

    boost::asio::streambuf buffer;
    boost::asio::async_read_until(out, buffer, "2", [&](boost::system::error_code code, std::size_t size) {
        if (code) {
            std::cerr << "Oops: " << code.message() << std::endl;
        } else {
            std::cerr << "received: " << size << " bytes: ";

            auto b = buffers_begin(buffer.data()), m = b+size, e = buffers_end(buffer.data());

            std::clog << std::quoted(std::string(b, m)) << std::endl;
            std::clog << "Note that we read more bytes: " << std::quoted(std::string(m, e)) << std::endl;

            buffer.consume(size);
        }
    });

    boost::asio::async_write(in, boost::asio::buffer("wo2rld\n", 7), [&](boost::system::error_code code, std::size_t size) {
        if (code) {
            std::cerr << "Oops: " << code.message() << std::endl;
        } else {
            std::cerr << "sent: " << size << " bytes: ";
        }
    });

    context.run();
    return c.exit_code();
}

Printing again:
sent: 7 bytes: received: 30 bytes: "reversed: olleh
reversed: dlr2"
Note that we read more bytes: "ow
"


It helped. Thanks. But now I am wondering what is the difference between cin.get() and getchar() because I tried first solution on both and it works only for cin.
