提升async_pipe不显示所有子过程输出
我遇到了一个障碍。下面的代码有问题,但这只是一个演示。我想首先使高级逻辑正确。
在到达“就绪”状态之前,这两个启动应用程序会输出大量启动信息。在此状态下,程序A可以通过STDIN为用户输入。程序B仅通过网络连接来聆听 - 最激烈的和记录数据。
理想情况下,使用此示例程序,我应该能够在“实时”中看到程序B的输出。但是在每个循环迭代中,什么都没有发生。我不确定它是否通过管道接收输入。
我以前在使用bp :: opstream
写信给孩子 - program a-stdin。我知道是否通过程序A通过其Async_pipe接受了一些命令,Progam B节目还显示了一些记录信息(例如“ Trip”)。这些是窗口控制台应用程序,我正在使用Boost C ++作为子过程与它们进行交互。
有人有任何想法吗?
std::size_t read_loop(bp::async_pipe& p, mutable_buffer buf, boost::system::error_code &err)
{
return p.read_some(buf, err);
}
void read_loop_async(bp::async_pipe& p, mutable_buffer buf, std::error_code &err) {
p.async_read_some(buf, [&p, buf, &err](std::error_code ec, size_t n) {
std::cout << "Received " << n << " bytes (" << ec.message() << "): '";
std::cout.write(boost::asio::buffer_cast<char const*>(buf), n) << std::endl;
err = ec;
if (!ec)
read_loop_async(p, buf, err);
});
}
void write_pipe(bp::async_pipe&p, mutable_buffer buf)
{
ba::async_write(p, buf, [](boost::system::error_code ec, std::size_t sz)
{
std::cout << "Size Written " << sz << " Ec: " << ec << " " << ec.message() << '\n';
});
}
int main()
{
bp::opstream sendToChild;
string wd = "<---path-to-working-dir----->";
ba::io_service ios;
string bin = "<path-to-bin-and-name>";
bp::async_pipe input_pipe(ios);
bp::async_pipe output_pipe(ios);
bp::child c(bin, "arg1", "arg2", "arg3", bp::std_out > output_pipe,
bp::std_in < input_pipe, ios, bp::start_dir(wd.c_str()));
size_t size = 8192;
string input;
vector <char> buffer(size);
boost::system::error_code ec;
std::error_code err;
ios.run();
while (1)
{
//show read whatever is available from the childs output_pipe
read_loop_async(output_pipe, bp::buffer(buffer), err);
cout << "\nBoot-> ";
cin >> input;
if (input == "1")
{
cout << " send input to child: ";
cin >> input;
//send commands to the child, Program A
//originally
//sendToChild << input<< endl;
write_pipe(input_pipe, bp::buffer(input));
}
if (input == "quit")
{
//sendToChild << input << endl;
read_loop_async(output_pipe, bp::buffer(buffer), err);
break;
}
ios.poll(ec);
ios.restart();
}
c.join();
cout << "done...";
cin >> input;
}
这是我遵循的链接: 如何尽快检索程序输出印刷?
I ran into a roadblock. The code below has issues, but this is just a demo; I want to get the high level logic correct first.
The two startup application output a lot of startup info, before arriving the the "ready" state. At this state, Program A is ready for user input via stdin. Program B just listens via network connection--ingest and record data.
Ideally, with this sample program, I should be able to see the output from Program B, in "real-time". But at each loop iteration, nothing happens; I'm not sure it's receiving input via its pipe.
I was previously using bp::opstream
to write to the child's--Program A--stdin. I know if some command are accepted to by Program A via its async_pipe, Progam B show also show some logging info (e.g. "trip"). These are window console applications, and I'm using Boost C++ to interact with them as child processes.
Does anyone have any ideas what's going on?
std::size_t read_loop(bp::async_pipe& p, mutable_buffer buf, boost::system::error_code &err)
{
return p.read_some(buf, err);
}
void read_loop_async(bp::async_pipe& p, mutable_buffer buf, std::error_code &err) {
p.async_read_some(buf, [&p, buf, &err](std::error_code ec, size_t n) {
std::cout << "Received " << n << " bytes (" << ec.message() << "): '";
std::cout.write(boost::asio::buffer_cast<char const*>(buf), n) << std::endl;
err = ec;
if (!ec)
read_loop_async(p, buf, err);
});
}
void write_pipe(bp::async_pipe&p, mutable_buffer buf)
{
ba::async_write(p, buf, [](boost::system::error_code ec, std::size_t sz)
{
std::cout << "Size Written " << sz << " Ec: " << ec << " " << ec.message() << '\n';
});
}
int main()
{
bp::opstream sendToChild;
string wd = "<---path-to-working-dir----->";
ba::io_service ios;
string bin = "<path-to-bin-and-name>";
bp::async_pipe input_pipe(ios);
bp::async_pipe output_pipe(ios);
bp::child c(bin, "arg1", "arg2", "arg3", bp::std_out > output_pipe,
bp::std_in < input_pipe, ios, bp::start_dir(wd.c_str()));
size_t size = 8192;
string input;
vector <char> buffer(size);
boost::system::error_code ec;
std::error_code err;
ios.run();
while (1)
{
//show read whatever is available from the childs output_pipe
read_loop_async(output_pipe, bp::buffer(buffer), err);
cout << "\nBoot-> ";
cin >> input;
if (input == "1")
{
cout << " send input to child: ";
cin >> input;
//send commands to the child, Program A
//originally
//sendToChild << input<< endl;
write_pipe(input_pipe, bp::buffer(input));
}
if (input == "quit")
{
//sendToChild << input << endl;
read_loop_async(output_pipe, bp::buffer(buffer), err);
break;
}
ios.poll(ec);
ios.restart();
}
c.join();
cout << "done...";
cin >> input;
}
Here is the link I followed:
How to retrieve program output as soon as it printed?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
唔。有很多东西要拆箱。首先:
奔跑直到孩子完成。如果子进程需要发送比缓冲区中的拟合更多的输出,则可能不会消耗
> ios.run()
,这很可能僵局。下一个
poll()
根据定义没有任何操作,因为您没有首先调用restart
。幸运的是,您忽略了错误代码,重新启动
接下来发生。然后,您会得到下一个问题,因为循环的下一个迭代以
read_loop_async(output_pipe,bp :: buffer(buffer),err),err);
表示,这意味着您,这意味着您具有通常禁止禁止的重叠读取操作( nofollow noreferrer“> nofellow noreferrer”> nofected行为)您正在使用相同的缓冲区。这本身就足以解释“丢失的数据”,因为是的,您在同一位置进行了多个读数,因此一个人会抓住另一个。也就是说,如果您可以理由,因为您不能关于UB的原因。
现在,我的眼睛斑点甚至是第三个调用
read_loop_async
。这没有道理。顾名思义,read_loop_async
已经是 loop :完成后自称:因此,只有1个调用可以预期。似乎您不掌握
async _*
initiation函数始终立即返回(因为操作已完成异步)。您分配了以下事实:其中
err
是启动函数的参考参数。它不是那样工作的。该错误仅在完成时可用。由于无论如何您似乎都不会在读取循环之外使用它,所以我将其丢弃。然后,它
绝对什么都不做,因为
sendtochild
实际上仅声明了,并且从未在其他地方使用。write_pipe
再次尝试使用async _
initiation,但不能,因为它是在同步输入循环中使用的。只是不要在那里使用异步。正如编写的那样,它是UB的另一个来源,因为buf
参数将指向std :: String
变量,该变量正在主要函数中突变。因此,简化:[注意它如何正确标记
buf
为const_buffer
。]现在,可能修复该
sendToChild
,我将用
ios.restart()
用Justpoll()
- )无论如何还为时过早。除上述内容外,我用
运算符替换了
,因为您很可能希望用户输入使用Enter键,而不是SPACE将用户输入界定。我还添加了std :: getline
调用“ \ n”
,就像您在sendToChild
行中一样,因为它有助于使用使用线条缓冲输入的简单测试子来演示。现在,我们将使用它作为测试孩子:
这意味着我们将输入反向回声和十六进制转储,以及最后的时间摘要。
清单
live on Coliru
有点固定的
在我的系统上更易于互动:
Hmm. There's a lot to unpack. First off:
runs until the child completes. It might well deadlock if the child process needs to send more output than fits in the buffers, sinc ye you don't consume any of it before doing
ios.run()
.The next
poll()
by definition does not do anything, because you didn't callrestart
first. Luckily you ignore the error codes andrestart
happens next.Then, you get the next problem, because the next iteration of the loop starts with another
read_loop_async(output_pipe, bp::buffer(buffer), err);
which means you have overlapping read operations which is usually forbidden (Undefined Behaviour), but runs into UB anyways here because you're using the same buffers.This in itself is more than enough to explain "lost data" since, yeah, you're doing multiple reads in the same location, so one would clobber the other. That is, if you could reason about it, because you cannot reason about UB.
Wierdly now my eye spots even a third invocation of
read_loop_async
. It makes no sense. As the name suggests,read_loop_async
is already a loop: it calls itself when completed:So, only 1 invocation would ever be expected. It seems like you don't grasp that
async_*
initiation functions always return immediately (because the operation completes asynchronously). This is also exemplified in the fact that you assign:Where
err
is a reference argument to the initiation function. It doesn't work like that. The error is only available on completion. Since you don't seem to use it outside the read loop anyways, I'll drop it.Then there's
Which does absolutely nothing, since
sendToChild
is literally only declared, and never used elsewhere.write_pipe
again tries to use anasync_
initiation, but it cannot, because it's being used in a synchronous input loop. Just don't use async there. As written it was another source of UB, because thebuf
argument would point to astd::string
variable that was being mutated in the main function. So, simplify:[Note how it correctly marks
buf
asconst_buffer
.]Now, probably fix that
sendToChild
use byI'll replace the
ios.restart()
stuff with justpoll()
- because we didn'trun()
it too early anyways.Other than the above, I replaced the
operator>>
withstd::getline
calls because it's most likely you want the user input to be delimited with Enter keys, not space. I also added"\n"
as you had in thesendToChild
line, because it helps demonstrating with a simple test child that uses line-buffered input.Now, we'll use this as a test child:
Which means we get our input echoed in reverse and hex dump, and a time summary at the end.
Somewhat Fixed Listing
Live On Coliru
Tested with
Prints
Which is easier to follow interactively on my system: