You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#使用Process.Start自动化执行UDEC程序时ReadToEnd死锁问题

C# 重定向Process标准流执行UDEC程序死锁解决方案

问题场景

  • 手动操作逻辑:双击启动udecConsole2017.exe后,控制台会输出插件加载、版本、授权等启动信息,待输出出现udec>命令提示符时,输入命令call 'D:\Work\202205\20220525\tunnel-for-cmd.txt'即可触发计算,输出计算结果。

启动阶段控制台输出(系统原因导致的乱码可忽略):

--- module2d plugin DFNModule2D loaded.
--- module2d plugin GeometryModule2D loaded.
--- module2d plugin Convert loaded.


                        U D E C: VERSION 7.00
               赏屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯突
               ?     Universal Distinct Element Code       ?
               掏屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯凸
               ?Copyright (c):Itasca Consulting Group 2017 ?
               ?                                           ?
               韧屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯图
                Licensee:      Itasca Consulting Group, Inc.
                               Minneapolis, Minnesota  USA
                Options:
                               Barton-Bandis
                               Creep
                               CppUdm
                               Flow
                               Thermal


                Memory:          4096 MBytes
                Precision:     Double
udec>

命令执行阶段输出:

udec>call 'D:\Work\202205\20220525\tunnel-for-cmd.txt'

 ................
 ................
 calculation results
 ................
 ................
  • 初始自动化实现代码:
try
{
    var psi = new ProcessStartInfo()
    {
        UseShellExecute = false,
        FileName = @"D:\Program Files\ITASCA\UDEC700\Exe64\udecConsole2017.exe",
        //Arguments = @"call 'D:\Work\202205\20220525\tunnel-for-cmd.txt'",
        RedirectStandardInput = true,
        RedirectStandardOutput = true,
        CreateNoWindow = true,
    };
    var p = System.Diagnostics.Process.Start(psi);
    // Read until the udec> prompt
    while (true)
    {
        //var line = p.StandardOutput.ReadLine();
        //if (line.StartsWith("udec>"))
        //    break;
        int v = p.StandardOutput.Read();
        Console.Write((char)v);
        if (v == 62)
        {
            break;
        }
        if (v == -1)
            break;
    }

    // Write the command
    Console.Write(@"call 'D:\Work\202205\20220525\tunnel-for-cmd.txt'");
    p.StandardInput.WriteLine(@"call 'D:\Work\202205\20220525\tunnel-for-cmd.txt'");
    p.StandardInput.Flush();

    // Read the result
    string content = p.StandardOutput.ReadToEnd();

    p.WaitForExit();
    Console.WriteLine(content);
   
}
catch (Exception e)
{
    Console.WriteLine(e.Message);
}
  • 故障表现:代码运行后可正常输出UDEC启动信息,成功识别udec>提示符并写入执行命令,但执行到string content = p.StandardOutput.ReadToEnd();语句时程序会挂起死锁、无响应,尝试异步读取、绑定OutputDataReceived事件调用BeginOutputReadLine()等方案均无法解决。

问题根因

死锁核心原因有两点:

  1. ReadToEnd()方法的返回条件是目标进程关闭标准输出流句柄,但UDEC是交互式控制台程序,执行完传入的call命令后不会退出进程,会重新回到udec>提示符等待下一条指令,标准输出流会一直保持打开状态,ReadToEnd()会无限阻塞等待流关闭。
  2. 原逻辑中判断提示符仅判断了字符>(ASCII码62),如果启动日志或计算结果中出现>字符会提前跳出读取循环,残留未读的缓冲区内容也会增加阻塞概率。

修复方案

  • 废弃ReadToEnd()逻辑,改为持续逐字符/逐行读取标准输出流,直到再次识别到命令执行完成后返回的udec>提示符,即可判定本次计算完成,无需等待进程退出。
  • 提示符判断逻辑增加前缀匹配,避免日志中其他>字符触发误判。
  • 计算完成后主动向标准输入写入程序退出指令,关闭UDEC进程避免后台残留。

修复后可运行代码:

using System;
using System.Diagnostics;
using System.Text;

try
{
    var psi = new ProcessStartInfo()
    {
        UseShellExecute = false,
        FileName = @"D:\Program Files\ITASCA\UDEC700\Exe64\udecConsole2017.exe",
        RedirectStandardInput = true,
        RedirectStandardOutput = true,
        CreateNoWindow = true,
        // 中文系统如果出现乱码可替换为Encoding.GetEncoding("GB2312")
        StandardOutputEncoding = Encoding.UTF8,
        StandardInputEncoding = Encoding.UTF8
    };
    var p = Process.Start(psi);
    StringBuilder outputCache = new StringBuilder();
    
    // 读取启动日志,等待首次出现udec>提示符
    while (true)
    {
        int readChar = p.StandardOutput.Read();
        if (readChar == -1) break; // 进程意外退出直接跳出
        char c = (char)readChar;
        Console.Write(c);
        outputCache.Append(c);
        // 匹配提示符,避免单个>字符误判
        if (outputCache.ToString().TrimEnd().EndsWith("udec>"))
        {
            break;
        }
    }

    outputCache.Clear();
    // 写入计算执行命令
    string execCommand = @"call 'D:\Work\202205\20220525\tunnel-for-cmd.txt'";
    p.StandardInput.WriteLine(execCommand);
    p.StandardInput.Flush();

    // 持续读取计算日志,等待命令执行完成后再次出现udec>提示符
    string calcResult = string.Empty;
    while (true)
    {
        int readChar = p.StandardOutput.Read();
        if (readChar == -1) break;
        char c = (char)readChar;
        Console.Write(c);
        outputCache.Append(c);
        string currentOutput = outputCache.ToString();
        if (currentOutput.TrimEnd().EndsWith("udec>"))
        {
            // 截取纯计算结果,剔除末尾提示符
            calcResult = currentOutput.Replace("udec>", "").Trim();
            break;
        }
    }

    // 写入退出命令关闭目标进程
    p.StandardInput.WriteLine("quit");
    p.StandardInput.Flush();
    p.WaitForExit();
    p.Close();

    // 按需使用calcResult即可
    Console.WriteLine("计算完成,结果如下:");
    Console.WriteLine(calcResult);
}
catch (Exception e)
{
    Console.WriteLine(e.Message);
}

优化提示:如果逐字符读取性能不满足要求,可替换为ReadLine()逐行读取,每次读取一行后判断行内容是否包含udec>提示符即可,逻辑完全一致,读取效率更高。

内容的提问来源于stack exchange,提问作者Lake_Lagunita

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 22:15:45