我有这个代码来测试Ackermann函数,我称之为程序 P1 。在ackerman(int m,int n)中。 我的目的是,如果尚未定义OUT,程序将运行并在完成后打印结果。如果定义了OUT,程序将在每个“循环”中打印“xxx”,并等待来自stdin的char输入。我有一个外部进程来读取 P1 的输出,捕获“xxx”字符串(做某事)并将一个字符写回 P1 ,因此它可以继续。 如果我编译没有定义OUT,并运行P1独立,代码可以完全运行,并打印出ack(3,6)= SomeValue,但如果我启用OUT,并使用P1运行外部进程,P1可以接收char一会儿,突然“暂停”,没有崩溃,没有错误,没有退出。我使用c变量来计算P1停止前的时间,这不是一个固定的数字(3813,3951,3804,....)。外部进程在C#中编写,并且经过了很好的测试。我在很多情况下使用它,但在这个ackermann功能中,它停止了。为什么它不会在第一个循环中停止,而是在相当多的循环中停止?印刷与停止之间是否有任何关系?
P1 :
int MAX = 99999;
class stack {
private:
int num[99999];
int size;
public:
stack() {
size = 0;
}
void push(long x) {
if(size < MAX)
num[++size] = x;
else {
cout<<"Full Stack"<<endl;
return;
}
}
int pop() {
if(size==0) {
cout<<"Out of stack memory"<<endl;
return -1;
}
return num[size--];
}
bool isEmpty() {
if(size == 0)
return true;
else
return false;
}
};
int ackman(int m,int n)
{
stack v;
v.push(m);
int c = 0;
while(!v.isEmpty()) {
m = v.pop();
if(m==0 ||n==0)
n+= m+1;
else {
v.push(--m);
v.push(++m);
n--;
}
c++;
#ifdef OUT
printf("c is %d\n",c );
cout << endl;
//flush(stdin);
//flush(stdout);
cout << "xxx" << endl;
getchar();
//sleep(200);
#endif
}
return n;
}
void ack()
{
int m = 3, n = 6;
#ifdef DEMO
m = 3;
n = 4;
#endif
try{
int k = ackman(m,n);
printf("Ack %d , %d = %d\n",m,n,k );
}catch(...){
cout << "Co loi khi ack";
}
}
//just example
int main(){
ack();
return 0;
}
外部流程
static List<BenchMemory> benchMemory(String exeName, String caseName)
{
int count = 0;
Console.Title = "Bench memory: " + exeName + " case: "+caseName;
Console.WriteLine("Exe: {0}, case: {1}", exeName, caseName);
using (Process process = new Process())
{
/* Create the start info object */
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = exeName + ".exe";
startInfo.Arguments = caseName;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardInput = true;
List<BenchMemory> listMemResult = new List<BenchMemory>();
#region handler
DataReceivedEventHandler outDataHandler = (object sender, DataReceivedEventArgs e) =>
{
if (e.Data != null)
{
count++;
Console.WriteLine(e.Data);
if (!process.HasExited && e.Data != null && e.Data.ToLower().Equals("xxx"))
{
var bMem = getProcessMemory(process, exeName, caseName);
listMemResult.Add(bMem);
process.StandardInput.WriteLine("k");
}
}
};
#endregion
process.StartInfo = startInfo;
process.OutputDataReceived += outDataHandler;
process.Start();
process.BeginOutputReadLine();
process.WaitForExit();
var topPeak = listMemResult.Take(10).ToList();
process.Refresh();
return topPeak;
}
}
答案 0 :(得分:3)
在C ++程序中添加fflush(stdin);
应该可以解决问题(修改后的代码片段):
#ifdef OUT
printf("c is %d\n",c );
cout << endl;
cout << "xxx" << endl;
fflush(stdin); // note
getchar();
#endif
出于调试目的,我还略微修改了你的C#代码,但没有什么值得看的:
DataReceivedEventHandler outDataHandler = (object sender, DataReceivedEventArgs e) =>
{
if (e.Data != null)
{
var senderProcess = sender as Process;
if(sender == null)
Console.Write("Sender == NULL?");
if(senderProcess.HasExited)
Console.WriteLine("Exited");
count++;
Console.WriteLine(e.Data);
// e.Data != null redundant check, already everything wrapped in if(e.Data != null)
if (e.Data.Trim().ToLower().Equals("xxx"))
{
senderProcess.StandardInput.Write("k");
Console.WriteLine("Pass");
}
}
};
我用WriteLine
取代Write
后,我在案件中得到的数字总是2047,WriteLine
打印两个字符,请注意\n
),我到了4095.再次2的力量(加+1)?缓冲?使用调试器StandardOutput
进行检查,您会注意到输出缓冲区中确实有4096个字符。此外,如果将断点设置为Write
,您会注意到在4095之后它会卡在那里(使用条件断点来缓解您的生活)并且永远不会到达Console.WriteLine("Pass")
。
StandardOutput.Flush
没有真正解决问题(在文档中也找不到原因),如果我没记错的话,getchar
也不会清除它。
将fflush(stdin)
添加到C ++程序会清除它,从而为C#继续在其中写入空间。