在浅顶软呢帽中管道干鱼行为不端

时间:2015-05-15 10:23:51

标签: c++ pipe virtual-machine fedora

在我的项目的某个地方,我使用fork和pipe来执行另一个进程并管道其I / O以与之通信(我用C ++编写)。当我在Ubuntu 14.04中编译它时没有问题,它可以正常工作,但我在一个WMWare虚拟机上的fedora中编译它,并且奇怪的事情开始发生。如果我在终端中运行二进制文件,则没有错误,但管道中不会写入任何内容(但是获取字符流将起作用)。我尝试在fedora中调试我的代码,我在我的代码中设置了一个断点,但是当进程试图从管道读取时(在终端中执行时没有信号),然后给出了一个损坏的管道信号。 那么,你们之前遇到过这样的问题吗? debian和red hat linux之间的管道有什么区别吗?或者是因为我在虚拟机上运行fedora?

CODE:

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] = '\0';

     output += readBuffer;
  }

  cout << "Got: " << output;
}

3 个答案:

答案 0 :(得分:0)

debian和red hat之间的管道没有区别,但以下问题列表可能会对您有所帮助:

- Ubuntu和Fedora使用相同的架构(64位对32位)?

- 您使用相同版本的gcc(或任何其他编译器)吗?

(建议:使用cerr进行错误输出,也可以使用调试输出 - &gt;你复制标准输出和输入,所以如果出现故障你可能看不到它)

答案 1 :(得分:0)

无论如何,这里是你如何把它变成一个独立的,可编辑的例子:

<强>鱼干

#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] = '\0';

      output += readBuffer;
    }

    cout << "Got: " << output;
  }

  return 0;
}

<强>输出:

The following string has been written to engine:
        uciGot: UCI

答案 2 :(得分:0)

我看到你正在使用干鱼。我也从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,但我肯定这是导致问题的原因。您可以通过删除锁定功能来检查它。

编辑:我忘了提到前面提到的基于linux的系统中的管道行为没有什么不同,但处理与管道一起使用的互斥锁的分布之间可能会有细微差别。