从 Process.Start() 调用时,C# 应用程序随机挂起

C# app hangs randomly when called from Process.Start()

我设置了一个 Windows 服务来管理自定义 .Net 任务。组织是:

-Windows 服务监控计划并根据需要启动 worker .exe。

-Worker .exe(轻量级 winform 应用程序)使用命令行参数来提取 DLL(插件)和 运行 一些代码。

这几个月来一直运行良好。我最近将它迁移到 Server 2012(从 2008 IIRC 开始)——这可能不相关,但很难说。迁移后一段时间以来,我遇到了一个问题,即 worker .exe "starts" 在被 process.start() 调用后,但没有到达我的代码。没有错误或任何错误,它似乎在应用程序加载期间冻结。

启动它的服务代码相当标准。

// Create a temp folder and copy the executable to it
// (so the source exe isn't always in use and can be swapped out)

Process p = new Process();
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = Path.Combine(temp.Path, Path.GetFileName(ExecutablePath));
psi.Arguments = CommandLineArgs.ConcatenateList(" ");
psi.UseShellExecute = false;
psi.RedirectStandardError = true;
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.CreateNoWindow = true;
psi.ErrorDialog = false;
psi.WindowStyle = ProcessWindowStyle.Hidden;
p.StartInfo = psi;
p.Start();

// read standard output if necessary, kill and reschedule if appears to be frozen, etc.

此时,worker 可执行文件启动 - 它在任务管理器中看起来基本正常。唯一让我知道出现问题的是内存消耗——在正常情况下,工作人员在启动期间达到大约 5MB 并增长以反映任务,但是当进程冻结时它只达到大约 2MB 并停止。

为了证明这不是我在工作程序中的任何代码,我在第一行添加了对日志记录函数的调用,但从未见过日志。

没有错误消息,而且 - 真正奇怪的是 - 这不是一个一致的问题。现在冻结的完全相同的调用将在 30 秒后 运行 正常。问题发生的时间似乎也没有任何真实模式 - 我看到的最接近的事情是它偶尔会同时发生在多个任务上(例如,它可能会影响在问题发生时开始的所有任务发生在任何任务中)。


我的服务可以自动检测并适当处理它,所以这不是一个紧急问题,但如果任何人都认为原因或解决方案突出,我仍然想解决这个问题。


worker 的初始化代码只是一个标准的 win 表单启动,我的东西开始在 form_load 中被调用。

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
}

public Form1()
{
    InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
    // Do Stuff - never gets hit when the freeze happens.
}

编辑:根据评论,设置服务以在看到挂起的进程时使用它创建的日志条目记录一个小型转储。明天会检查它,看看会发生什么。


编辑 2015 年 9 月 4 日:小型转储信息:

小型转储在 static void main 的退出 } 处显示代码 stopped/stuck,即:

static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form1());
} // <------ This is where the main thread is frozen.

否则一切似乎都很好。

为了以防万一,我将进行一些研究并尝试对 worker 进行一些更改。


编辑 2015 年 9 月 4 日#2: 调整了工作人员启动,它似乎正在工作。它的要点是删除表单引用并仅使用应用程序上下文(例如 codeproject sample

我用任务请求重击了系统,但没有任何问题。我将在周末 运行 进行测试,并在周二进行状态更新。 仍然很好奇为什么它会随着表单加载而随机中断。

现在的代码:

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.Run(new AppContext());
    }
}

class AppContext : ApplicationContext
{
    public AppContext()
    {
        // Do Stuff
    }
}

我还不能在你的 post 上添加评论(我会因为这样做而被其他 Whosebug 用户毁掉,但是......)

我遇到的问题和你的很相似。我的问题来自服务启动的会话。在迁移期间,该服务在新 OS 中的 "Session 0" 中启动,而不是作为 "system" 程序启动。它是在我们程序的许可下通过服务发布到 运行 的。 也许你应该检查这一点。

对不起,如果我把它作为答案而不是在评论中说出来

根据最后的说明,将表单位全部拉出似乎已经解决了这个问题。在这一点上,我假设服务器 2012 不喜欢在某些情况下不显示的 winform 应用程序;因为它大部分时间都有效,而且表单代码没有任何变化。

服务:

// Create a temp folder and copy the executable to it
// (so the source exe isn't always in use and can be swapped out)

Process p = new Process();
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = Path.Combine(temp.Path, Path.GetFileName(ExecutablePath));
psi.Arguments = CommandLineArgs.ConcatenateList(" ");
psi.UseShellExecute = false;
psi.RedirectStandardError = true;
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.CreateNoWindow = true;
psi.ErrorDialog = false;
psi.WindowStyle = ProcessWindowStyle.Hidden;
p.StartInfo = psi;
p.Start();

// read standard output if necessary, kill and reschedule if appears to be frozen, etc.

工人:

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.Run(new AppContext());
    }
}

class AppContext : ApplicationContext
{
    public AppContext()
    {
        // Do Stuff
    }
}