C#进程不会停止执行

时间:2013-02-16 10:33:58

标签: c# process

我遇到的问题是C#2008 Windows应用程序没有完成执行,我正在尝试确定如何解决问题。最初编写C#2010控制台应用程序来调用C#2008控制台应用程序,后者又调用Web服务。我将这两个应用程序都更改为Windows应用程序,因为我不想让dos弹出窗口。

问题是被叫C#2008的Windows应用程序从未完成执行。这个过程留在记忆中。

下面列出的代码是C#2010应用程序代码的一部分。

private static Logger logger = LogManager.GetCurrentClassLogger(); 
try
{
    Process eProcess = new Process();
    strConsoleAppLocation = ConfigurationManager.AppSettings["client_location"];
    String Process_Arguments = null;
    eRPT_Process.StartInfo.UseShellExecute = false;
    eRPT_Process.StartInfo.FileName = strConsoleAppLocation;
    Process_Arguments = " 1 CLI";
    eProcess.StartInfo.Arguments = Process_Arguments;
    eProcess.Start();
    eProcess.WaitForExit(1800);
    Process_Arguments = null;
    eProcess.StartInfo.UseShellExecute = false;
    Process_Arguments = " 2 TIM";
    eProcess.StartInfo.Arguments = Process_Arguments;
    eProcess.Start();
    eProcess.WaitForExit(1800);
    eProcess.Dispose();
    Process_Arguments = null;
}
catch (Exception e)
{
    logger.Error(e.Message + "\n" + e.StackTrace);
} 

我知道C#2008应用程序永远不会通过查看内存中的进程来完成。另外,如果我将代码行更改为以下代码:eProcess.WaitForExit();,则应用程序永远不会返回到被调用的程序。

在C#2008调用的应用程序中,执行的最后一行代码如下:

Environment.Exit(1);   

因此,要解决此问题,我有以下问题:

  1. 如果您有关于如何更改上面列出的代码的建议,您能告诉我您的建议是什么吗?

  2. 由于这2个程序现在正在生产中,我想知道你是否有关于我如何解决这个问题的建议“绑带”修复?有没有办法可以阻止C#2010程序完成执行时运行的C#2008进程?有没有办法让C#2008应用程序在执行完毕后终止自己的进程?如果是这样,你能告诉我如何解决这个问题的代码吗?

  3. 对于长期修复,您能告诉我如何确定C#2008进程没有停止的原因以及如何解决它?我会使用profiler,但我的公司只有visual studio 2010的专业版。所以你能告诉我你的建议是什么吗?

4 个答案:

答案 0 :(得分:3)

WaitForExit(),即等待它等待结束的进程无限期等待,而WaitForExit(int milliseconds)等待指定的持续时间然后超时。

根据您的编写,您从C#2010程序启动的C#2008程序永远不会终止。这可能是由于一些原因造成的。

  • 可能正在等待用户输入。

  • 它可能陷入无限循环。

  • 如果它是多线程的,其中一个线程可能没有完成执行,并且保持进程处于活动状态(如果线程未设置为后台线程)。

尝试直接从命令行运行它,看看它在做什么。

如果C#2008程序的行为在从命令行执行时是正确的/正如预期的那样,但是当从C#2010程序执行时它的行为有所不同,那么在两种情况下验证参数是否匹配。

您可以使用pskill终止正在运行的进程。你可以这样做:

if (!process.WaitForExit(1800))
{
    // launch a process for pskill to kill the C# 2008 program
}

最后,您可以通过打开C#解决方案/项目来调试正在运行的程序,然后使用Attach to Process命令,您可以在Visual Studio中的Debug菜单栏项下找到该命令。 / p>

答案 1 :(得分:0)

  1. 不,您不能直接在代码中输入pskill。您必须使用System.Diagnostics.Process类启动一个与您当前正在为C#2008程序进行的过程。

  2. 您是对的,您将使用Visual Studio附加到流程中,无论项目的创建版本是什么。一旦打开程序的解决方案,请单击Debug\Attach to Process。它将显示计算机上正在运行的进程列表。其中一列(通常是第一列)显示可执行文件的名称,该名称将与您的C#2008应用程序名称相匹配。在可疑的代码行上放置一个断点后,在列表中选择C#2008程序并单击Attach按钮。

  3. 我不确定你的意思。

  4. 调试几乎是你能够弄清楚发生了什么的唯一方法。

  5. 我刚刚注意到重新阅读你的问题。您已将C#2008应用程序转换为Windows应用程序,这是正确的吗?那不是你想要的。 Windows应用程序必须以某种方式终止并需要交互。您应该将两个应用程序转换回控制台应用程序,并确保在创建Process对象以启动C#2008应用程序时,将CreateNoWindow参数的ProcessStartInfo属性设置为{{1} } constructor as true。

    所以,比如:

    Process

    您可以进一步重构此代码,因为我正在重复创建public class Processor { private static Logger logger = LogManager.GetCurrentClassLogger(); private ProcessStartInfo MakeProcessStartInfo(string fileName, string arguments) { return new ProcessStartInfo { CreateNoWindow = true, UseShellExecute = false, FileName = fileName, Arguments = appArguments }; } public void CallExternalApplications() { try { var fileName = ConfigurationManager.AppSettings["client_location"]; using (var process = new Process { StartInfo = MakeProcessStartInfo(fileName, " 1 CLI") }) { process.Start(); if (!process.WaitForExit(1800)) { // create a Process here for pskill to kill the "process" using process.Id. } } using (var process = new Process { StartInfo = MakeProcessStartInfo(fileName, " 2 TIM") }) { process.Start(); if (!process.WaitForExit(1800)) { // create a Process here for pskill to kill the "process" using process.Id. } } } catch (Exception e) { // you really should be using logger.ErrorException(e.Message, e) here // and be using the ${exception} layoutrenderer in the layout in the NLog.config file logger.Error(e.Message + "\n" + e.StackTrace); } } } 对象的代码。我使用process块隐式调用using对象上的Dispose;这使代码更清晰,更易读。

    关键位是设置process对象的CreateNoWindow属性,一旦将应用程序从Windows应用程序转换回控制台应用程序,就会阻止控制台窗口弹出。

答案 2 :(得分:0)

这是我将ctrl-c发送到进程的解决方案。仅供参考,我从未让process.WaitForExit工作。

我没有使用GenerateConsoleCtrlEvent,而是找到了将CTRL-C发送到进程的方法。仅供参考,在这种情况下,我不需要找到组进程ID。

using System;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

public class ConsoleAppManager
{
    private readonly string appName;
    private readonly Process process = new Process();
    private readonly object theLock = new object();
    private SynchronizationContext context;
    private string pendingWriteData;

    public ConsoleAppManager(string appName)
    {
        this.appName = appName;

        this.process.StartInfo.FileName = this.appName;
        this.process.StartInfo.RedirectStandardError = true;
        this.process.StartInfo.StandardErrorEncoding = Encoding.UTF8;

        this.process.StartInfo.RedirectStandardInput = true;
        this.process.StartInfo.RedirectStandardOutput = true;
        this.process.EnableRaisingEvents = true;
        this.process.StartInfo.CreateNoWindow = true;

        this.process.StartInfo.UseShellExecute = false;

        this.process.StartInfo.StandardOutputEncoding = Encoding.UTF8;

        this.process.Exited += this.ProcessOnExited;
    }

    public event EventHandler<string> ErrorTextReceived;
    public event EventHandler ProcessExited;
    public event EventHandler<string> StandartTextReceived;

    public int ExitCode
    {
        get { return this.process.ExitCode; }
    }

    public bool Running
    {
        get; private set;
    }

    public void ExecuteAsync(params string[] args)
    {
        if (this.Running)
        {
            throw new InvalidOperationException(
                "Process is still Running. Please wait for the process to complete.");
        }

        string arguments = string.Join(" ", args);

        this.process.StartInfo.Arguments = arguments;

        this.context = SynchronizationContext.Current;

        this.process.Start();
        this.Running = true;

        new Task(this.ReadOutputAsync).Start();
        new Task(this.WriteInputTask).Start();
        new Task(this.ReadOutputErrorAsync).Start();
    }

    public void Write(string data)
    {
        if (data == null)
        {
            return;
        }

        lock (this.theLock)
        {
            this.pendingWriteData = data;
        }
    }

    public void WriteLine(string data)
    {
        this.Write(data + Environment.NewLine);
    }

    protected virtual void OnErrorTextReceived(string e)
    {
        EventHandler<string> handler = this.ErrorTextReceived;

        if (handler != null)
        {
            if (this.context != null)
            {
                this.context.Post(delegate { handler(this, e); }, null);
            }
            else
            {
                handler(this, e);
            }
        }
    }

    protected virtual void OnProcessExited()
    {
        EventHandler handler = this.ProcessExited;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
    }

    protected virtual void OnStandartTextReceived(string e)
    {
        EventHandler<string> handler = this.StandartTextReceived;

        if (handler != null)
        {
            if (this.context != null)
            {
                this.context.Post(delegate { handler(this, e); }, null);
            }
            else
            {
                handler(this, e);
            }
        }
    }

    private void ProcessOnExited(object sender, EventArgs eventArgs)
    {
        this.OnProcessExited();
    }

    private async void ReadOutputAsync()
    {
        var standart = new StringBuilder();
        var buff = new char[1024];
        int length;

        while (this.process.HasExited == false)
        {
            standart.Clear();

            length = await this.process.StandardOutput.ReadAsync(buff, 0, buff.Length);
            standart.Append(buff.SubArray(0, length));
            this.OnStandartTextReceived(standart.ToString());
            Thread.Sleep(1);
        }

        this.Running = false;
    }

    private async void ReadOutputErrorAsync()
    {
        var sb = new StringBuilder();

        do
        {
            sb.Clear();
            var buff = new char[1024];
            int length = await this.process.StandardError.ReadAsync(buff, 0, buff.Length);
            sb.Append(buff.SubArray(0, length));
            this.OnErrorTextReceived(sb.ToString());
            Thread.Sleep(1);
        }
        while (this.process.HasExited == false);
    }

    private async void WriteInputTask()
    {
        while (this.process.HasExited == false)
        {
            Thread.Sleep(1);

            if (this.pendingWriteData != null)
            {
                await this.process.StandardInput.WriteLineAsync(this.pendingWriteData);
                await this.process.StandardInput.FlushAsync();

                lock (this.theLock)
                {
                    this.pendingWriteData = null;
                }
            }
        }
    }
}

然后,在实际运行该过程并在我的主应用程序中发送CTRL-C:

            DateTime maxStartDateTime = //... some date time;
            DateTime maxEndDateTime = //... some later date time
            var duration = maxEndDateTime.Subtract(maxStartDateTime);
            ConsoleAppManager appManager = new ConsoleAppManager("myapp.exe");
            string[] args = new string[] { "args here" };
            appManager.ExecuteAsync(args);
            await Task.Delay(Convert.ToInt32(duration.TotalSeconds * 1000) + 20000);

            if (appManager.Running)
            {
                // If stilll running, send CTRL-C
                appManager.Write("\x3");
            }

有关详细信息,请参阅Redirecting standard input of console applicationWindows how to get the process group of a process that is already running?

答案 3 :(得分:-1)

这就像魅力

而不是process.WaitForExit()我使用这种方法:

while (!process.StandardOutput.EndOfStream)
{
    Console.WriteLine(process.StandardOutput.ReadLine());
}