在软呢帽的管道stock鱼不当行为
piping stockfish misbehaves in fedora
我项目的某个地方我使用叉子和管道执行另一个过程并将其I/O进行管道与之通信(我正在用C 编写)。当我在Ubuntu 14.04中编译它时,它的工作正常,但是我用WMware虚拟机在Fedora中进行了编译,并且发生了奇怪的事情。如果我以终端运行二进制文件,则没有错误,但是管道中什么也不会写(但是要获得字符流可以起作用)。我试图在Fedora中调试代码,在代码中提出了一个断点,但是当过程试图从管道中读取过程时,发出了损坏的管道信号(在终端执行时没有信号)。那么,你们中的任何人以前遇到过这样的问题吗?Debian和Red Hat Linux之间的管道有什么区别?还是因为我在虚拟机上运行fedora?
代码:
int mFD_p2c [2];
int mFD_c2p [2];
int mEnginePID;
if (pipe(mFD_p2c) != 0 || pipe(mFD_c2p) != 0)
{
cout << "Failed to pipe";
exit(1);
}
mEnginePID = fork();
if (mEnginePID < 0)
{
cout << "Fork failed";
exit(-1);
}
else if (mEnginePID == 0)
{
if (dup2(mFD_p2c[0], 0) != 0 ||
close(mFD_p2c[0]) != 0 ||
close(mFD_p2c[1]) != 0)
{
cout << "Child: failed to set up standard input";
exit(1);
}
if (dup2(mFD_c2p[1], 1) != 1 ||
close(mFD_c2p[1]) != 0 ||
close(mFD_c2p[0]) != 0)
{
cout << "Child: failed to set up standard output";
exit(1);
}
string engine = "stockfish";
execlp(engine.c_str(), (char *) 0);
cout << "Failed to execute " << engine;
exit(1);
}
else
{
close(mFD_p2c[0]);
close(mFD_c2p[1]);
string str = "uci";
int nbytes = str.length();
if (write(mFD_p2c[1], str.c_str(), nbytes) != nbytes)
{
cout << "Parent: short write to child";
exit(1);
}
cout << "The following string has been written to engine:n"
<< string(1, 't') << str;
char readBuffer[2];
string output = "";
while (1)
{
int bytes_read = read(mFD_c2p[0], readBuffer, sizeof(char));
if (readBuffer[0] == 'n')
break;
readBuffer[bytes_read] = ' ';
output += readBuffer;
}
cout << "Got: " << output;
}
我看到您正在使用Stockfish。我也从Stockfish经历了这种行为。问题在于它处理输出的方式。在misc.h
中定义:
#define sync_cout std::cout << IO_LOCK
再次查看代码,我们将看到IO_LOCK
是一个枚举,用于COUT的超载朋友操作员:
std::ostream& operator<<(std::ostream& os, SyncCout sc) {
static Mutex m;
if (sc == IO_LOCK)
m.lock();
if (sc == IO_UNLOCK)
m.unlock();
return os;
}
我在这里看到的是,在使用COUT时,互惠倍锁定。我不知道这对Cout在管道中而不是Stdout中的输出有何影响,但是我很肯定这是造成问题的原因。您可以通过删除锁功能来检查它。
edit :我忘了提到以前提到的基于Linux的系统中的管道行为没有差异,但是分布之间可能会有略有差异处理与管道一起使用的静音。
<</p> <</p>Debian和Red Hat之间没有差异,但是以下问题列表可能会帮助您:
- 使用相同的体系结构(64位vs 32)?
使用Ubuntu和Fedora- 您使用相同版本的GCC(或任何其他编译器)吗?
(建议:使用CERR进行错误输出,也许您的调试输出 ->您dup标准输出和输入,因此,如果某物失败,您可能看不到它)
无论如何,这就是将其变成独立的,可编译的示例的方式:
Stockfish
#cat stockfish
tr a-z A-Z #just so we do something
echo #need to end with a "n" or else the parent won't break out of the while loop
运行命令:
make pipes && PATH=.:$PATH pipes
pipes.cc
//pipes.cc
#include <iostream>
#include <fstream>
#include <string>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
using namespace std;
int mFD_p2c [2];
int mFD_c2p [2];
int mEnginePID;
if (pipe(mFD_p2c) != 0 || pipe(mFD_c2p) != 0)
{
cout << "Failed to pipe";
exit(1);
}
mEnginePID = fork();
if (mEnginePID < 0)
{
cout << "Fork failed";
exit(-1);
}
else if (mEnginePID == 0)
{
if (dup2(mFD_p2c[0], 0) != 0 ||
close(mFD_p2c[0]) != 0 ||
close(mFD_p2c[1]) != 0)
{
cout << "Child: failed to set up standard input";
exit(1);
}
if (dup2(mFD_c2p[1], 1) != 1 ||
close(mFD_c2p[1]) != 0 ||
close(mFD_c2p[0]) != 0)
{
cout << "Child: failed to set up standard output";
exit(1);
}
string engine = "stockfish";
char *const args[]={};
int ret;
execvp(engine.c_str(), args);
//I need the endl here or else it doesn't show for me when the execvp fails; I wasn't able to compile the original exec command so I used a different one from the exec* family
cout << "Failed to execute " << engine << endl;
exit(1);
}
else
{
close(mFD_p2c[0]);
close(mFD_c2p[1]);
string str = "uci";
int nbytes = str.length();
if (write(mFD_p2c[1], str.c_str(), nbytes) != nbytes)
{
cout << "Parent: short write to child";
exit(1);
}
//My particular child process tries to read to the end, so give it the EOF
close(mFD_p2c[1]);
cout << "The following string has been written to engine:n"
<< string(1, 't') << str;
char readBuffer[2];
string output = "";
while (1)
{
int bytes_read = read(mFD_c2p[0], readBuffer, sizeof(char));
if (readBuffer[0] == 'n')
break;
readBuffer[bytes_read] = ' ';
output += readBuffer;
}
cout << "Got: " << output;
}
return 0;
}
输出:
The following string has been written to engine:
uciGot: UCI
- 理解boost::asio-async_read在无需读取内容时的行为
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- arr[-1]在c++中的奇怪行为
- 继承期间显示未知行为的子类
- 如何在c++中使用引用实现类似python的行为
- G锁定铸造到基础上会释放模拟行为
- 在C++中对T*类型执行std::move的意外行为
- std::当在256字节边界上写入整数时,流的奇怪行为
- 不知道某个东西是否被忽略会引入未定义的行为吗
- 奇怪的构造函数行为
- 重载运算符new[]的行为取决于析构函数
- 不同语言中相同代码的不同行为
- 在软呢帽的管道stock鱼不当行为
- 快速 XML 解析不当行为
- 查看实施不当行为
- 计时器、线程和编译器不当行为
- 将函数地址转换为 64 位整数:未定义/行为不当
- 由于内存重用不当而导致的未定义行为
- 向量<bool>::运算符[] 不当行为?
- 为什么这个initializer_list在传递字符串时使用不当行为