gpt4 book ai didi

c# - 即使不使用 RedirectStandardError/RedirectStandardOutput,Process.WaitForExit 也会挂起

转载 作者:行者123 更新时间:2023-12-03 14:45:12 25 4
gpt4 key购买 nike

我们有一个服务,它启动一个进程并在服务停止时等待进程退出/服务用户调用停止(停止/终止服务启动的进程)。

偶尔,process.waitForExit(TimeSpan)挂起。

请注意,由 Service 启动的进程是 native 进程(C++/CLI)进程,而服务是在 C# 中。

以下是我们正在使用的代码片段

public class ApplicationProcessControl : IProcessControl
{
private Process _proc;
private const int ProcessIdleTimeout = 5000;

public bool Start(string arguments)
{
if (IsAlive)
{
Log.TraceInfo("Application process already running. Killing it now...");
_proc.Kill();
}

var eProcStarted = new Mutex(false, "Mutex111");

_proc = new Process { EnableRaisingEvents = true, StartInfo = new ProcessStartInfo(_exePath, arguments) { RedirectStandardOutput = false,RedirectStandardError = false};
_proc.Exited += OnProcessExited;

_proc.Start();
bool started;
if(_proc == null)
{
Log.TraceInfo("Unable to start application process");
started = false;
}
else
{
started = eProcStarted.WaitOne(ProcessIdleTimeout);

if(started)
{
Log.TraceInfo($"Application process with id {_proc.Id} started successfully");
}
}
eProcStarted.Dispose();
return started;
}

public void Kill()
{
_proc.Kill();
}

public bool WaitForProcessToExit(TimeSpan timeout)
{
return _proc.WaitForExit((int) timeout.TotalMilliseconds);
}

public event Action ProcessExited;

private void OnProcessExited(object sender, EventArgs e)
{
var proc = sender as Process;

if(proc != null)
{
proc.Exited -= OnProcessExited;

if(proc.ExitCode == 0)
{
Log.TraceInfo("Application process exited gracefully");
}
else
{
Log.DeveloperWarning("Application process exited unexpectedly with code {0}", proc.ExitCode);
OnProcessExited();
}
}
}

private void OnProcessExited()
{
Action handler = ProcessExited;
handler?.Invoke();
}
}

public interface IProcessControl
{
bool IsAlive { get; }

bool Start(string arguments);

bool WaitForProcessToExit(TimeSpan timeout);

void Kill();

event Action ProcessExited;
}

public class ApplicationClientService: DisposableObject, IComponentService, ITaskControl, IUIControl,
IDataProvider<AngleFlavors>, IApplicationCloseNotifier
{
//...
private readonly IProcessControl _procCtrl;

public ApplicationClientService(IObjectProvider objPro)
{
//...
_procCtrl.ProcessExited += OnApplicationProcessExited;
}

public void Stop()
{
//...
CleanUpAppProcess();
//...
}


private void CleanUpAppProcess()
{
//...

if(!_procCtrl.WaitForProcessToExit(TimeSpan.FromSeconds(5)))
{
_procCtrl.Kill();
}
}

private void OnApplicationProcessExited()
{
if(!_isAppRunning)
{
return;
}

_isAppRunning = false;
_autoLaunchRequested = false;
RaiseApplicationClosed();
Log.DeveloperWarning("Application process closed unexpectedly");
Log.UserMessageApplicationClosedUnexpectedly();
...
}

protected virtual void RaiseApplicationClosed()
{
//AuditApplicationStop();
//ApplicationClosed?.Invoke();
}

}

最佳答案

不知道这是否可以回答您的问题(我自己的问题多于答案),但是这段代码:

    private void CleanUpAppProcess()
{
//...

if(!_procCtrl.WaitForProcessToExit(TimeSpan.FromSeconds(5)))
{
_procCtrl.Kill();
}
}

在 Kill 命令之前调用 WaitForExit。您是否希望进程在 5 秒内自行终止/由用户终止?正如 Bennie Zhitomirsky 在他的评论中指出的那样,互斥锁在应该拥有的时候没有被拥有(如果我正确理解了你想要实现的目标,如果没有,抱歉)。 IsAlive 的实现呢?

无论如何,我为 ApplicationProcessControl 类写了一些行。我只是用一些 native 进程对其进行了一些测试,似乎可以正常工作(但是,我不确定这是否是您要实现的目标):
    public class ApplicationProcessControl : IProcessControl
{
/// <summary>
/// Process instance variable.
/// </summary>
private Process _proc;
/// <summary>
/// The thread will try to acquire the mutex for a maximum of _mutexAcquireTimeout ms.
/// </summary>
private const int _mutexAcquireTimeout = 5000;
/// <summary>
/// Global static named mutex, seen by all threads.
/// </summary>
private static Mutex SpawnProcessMutex = new Mutex(false, "Mutex111");
/// <summary>
/// The state of the process.
/// </summary>
public bool IsAlive
{
get { return !(_proc is null) && !_proc.HasExited; }
}
/// <summary>
/// Spawns a new process.
/// </summary>
public bool Start(string arguments)
{
// Try to acquire the mutex for _mutexAcquireTimeout ms.
if (!SpawnProcessMutex.WaitOne(_mutexAcquireTimeout) || IsAlive)
{
// Mutex is still owned (another thread got it and is trying to run the process)
// OR the process is already running.
// DO NOT start a new process.
return false;
}

try
{
// Mutex is acquired by this thread.
// Create a new instance of the Process class.
_proc = new Process
{
EnableRaisingEvents = true,
StartInfo = new ProcessStartInfo("the_process_to_be_run", arguments)
{
RedirectStandardOutput = false,
RedirectStandardError = false
}
};
// Subscription to the ProcessExited event.
_proc.Exited += OnProcessExited;
// Run the process.
var haveAnHandle = _proc.Start();

// *******
// TODO: The process started but we may not have an handle to it. What to do?
// *******

//Log.TraceInfo($"Application process with id {_proc.Id} started successfully");
return true;
}
catch (Exception) // TODO: [Catch the specific exceptions here]
{
// The process failed to start, still we have an instance of Process with no use.
if (!(_proc is null))
{
_proc.Dispose();
_proc = null;
}
//Log.TraceInfo("Unable to start application process");
return false;
}
finally
{
// Release the mutex, another thread may be waiting to acquire it.
SpawnProcessMutex.ReleaseMutex();
}
}
/// <summary>
/// Kills the process started by the Start method.
/// </summary>
public void Kill()
{
if (IsAlive) _proc.Kill();
}
/// <summary>
/// Can't see a real reason to block the thread waiting synchronously for the process to
/// exit, we are already subscribed to the Exited event.
/// Kept here to avoid breaking the interface contract.
/// </summary>
public bool WaitForProcessToExit(TimeSpan timeout)
{
return _proc.WaitForExit((int)timeout.TotalMilliseconds);
}
/// <summary>
/// Client class consumable event to know the the process actually terminated.
/// </summary>
public event Action ProcessExited;
/// <summary>
/// Process Exited event handler.
/// </summary>
private void OnProcessExited(object sender, EventArgs e)
{
// Get a reference to the actual Process object.
var proc = sender as Process;
if (proc is null) return;

proc.Exited -= OnProcessExited;

if (proc.ExitCode == 0)
{
// Log.TraceInfo("Application process exited gracefully");
}
else
{
// Log.DeveloperWarning("Application process exited unexpectedly with code {0}", proc.ExitCode);
ProcessExited?.Invoke();
}
}
}

关于c# - 即使不使用 RedirectStandardError/RedirectStandardOutput,Process.WaitForExit 也会挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50212722/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com