当我从 ac# 库调用 Taskkill 以清除 WerFault.exe 进程时,Taskkill (讽刺地)挂起
我正在尝试使用 taskkill 关闭从 nunit 运行的负载测试期间产生的 WerFault 进程。每当测试启动的外部进程失败时,就会创建 WerFault.exe,因为它无法连接到它使用的服务,或者因为内存不足。暂时考虑这样一个事实,即这是将负载放入系统的一种相当复杂的方式,我宁愿与我直接将负载放入的服务进行交互,这是暂时结束的一种手段,而不是长期解决方案。
这些进程是非托管的 c++ exe,所以我不能使用 Process.GetProcessesByName(processName) 然后 process.kill 结果。
我在下面的示例中放置了一个潜在的修复程序,但是直到稍后我才能对此进行测试,因为我需要运行大量迭代来强制执行 WerFault.exe。欢迎任何建议!
这是我到目前为止得到的: -
processName.KillProcessesByName(true);
public static void KillProcessesByName(this string processname, bool useCommandLine)
{
if (useCommandLine)
{
using (var cmd = new ProcessRunner(new ProcessStartInfoWrapper
{
CreateNoWindow = true,
FileName = "cmd.exe",
RedirectStandardInput = true,
RedirectStandardError = true,
RedirectStandardOutput = true,
UseShellExecute = false
}))
{
string format = string.Format("cmd.exe /k \"taskkill /F /T /IM \"\"{0}\"\"\"", processname);
// string format = string.Format("taskkill /F /T /IM \"{0}\"", processname); // leaves taskkill hanging
Console.WriteLine(format);
cmd.SendInput(format);
//format = string.Format("taskkill /F /T /IM \"taskkill\"");
//cmd.SendInput(format);
}
}
else
{
processname.KillProcessesByName();
}
}
这是 Process runner 类:-
public class ProcessRunner : IProcessRunner
{
private readonly IList<string> _standardErrorOutputList;
private readonly IList<string> _standardOutputList;
bool _disposed;
public ProcessRunner(IProcessStartInfoWrapper processStartInfoWrapper)
{
ProcessStartInfoWrapper = processStartInfoWrapper;
ProcessStartInfoWrapper.SetupProcessStartInfo();
Process = new Process {StartInfo = ProcessStartInfoWrapper.ProcessStartInfo};
NewProcessStarted = Process.Start();
if (ProcessStartInfoWrapper.RedirectStandardOutput)
{
_standardOutputList = new List<string>();
Process.OutputDataReceived += StandardOutputHandler;
Process.BeginOutputReadLine();
}
if (ProcessStartInfoWrapper.RedirectStandardError)
{
_standardErrorOutputList = new List<string>();
Process.ErrorDataReceived += StandardErrorOutputHandler;
Process.BeginErrorReadLine();
}
//defer assigning the process to the job until the stdOutput has been redirected so that no messages are missed
AssignProcessToJobObject(_job, Process.Handle);
if (ProcessStartInfoWrapper.RedirectStandardInput)
{
StreamWriter = Process.StandardInput;
}
}
/// <summary>
/// ToDo:- create an extension class for IProcessRunner and add this as a default implementation of
/// StandardOutputHandler
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void StandardOutputHandler(object sender, DataReceivedEventArgs e)
{
lock (_standardOutputList)
{
_standardOutputList.Add(e.Data);
}
}
public void StandardErrorOutputHandler(object sender, DataReceivedEventArgs e)
{
lock (_standardErrorOutputList)
{
_standardErrorOutputList.Add(e.Data);
}
}
public void SendInput(string input)
{
StreamWriter.WriteLine(input);
}
public void WaitForStandardOutputToContainText(string expectedText, int waitTimeMilliSeconds)
{
WaitForListToContainText(_standardOutputList, expectedText, waitTimeMilliSeconds);
}
public void WaitForStandardErrorOutputToContainText(string expectedText, int waitTimeMilliSeconds)
{
WaitForListToContainText(_standardErrorOutputList, expectedText, waitTimeMilliSeconds);
}
public IProcessStartInfoWrapper ProcessStartInfoWrapper { get; set; }
public Process Process { get; private set; }
public bool NewProcessStarted { get; set; }
/// <summary>
/// publicly returns a copy of the StandardOutputList, while locking the backing field to prevent any changes
/// when the copy has been returned, the lock is released, and other threads can write to the property or its backing
/// field
/// </summary>
public IList<string> StandardOutputList
{
get
{
lock (_standardOutputList)
{
return SetShadowList(_standardOutputList);
}
}
}
public IList<string> StandardErrorOutputList
{
get
{
lock (_standardErrorOutputList)
{
return SetShadowList(_standardErrorOutputList);
}
}
}
public StreamWriter StreamWriter { get; private set; }
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
// Free any other managed objects here.
//
//todo:- implement Log4Net
// ReSharper disable EmptyGeneralCatchClause
int processId = default(int);
try
{
processId = Process.Id;
}
catch
{
}
try
{
if (ProcessStartInfoWrapper.RedirectStandardOutput)
{
Process.OutputDataReceived -= StandardOutputHandler;
_standardOutputList.Clear();
}
}
catch
{
}
try
{
if (ProcessStartInfoWrapper.RedirectStandardError)
{
Process.ErrorDataReceived -= StandardOutputHandler;
_standardErrorOutputList.Clear();
}
}
catch
{
}
try
{
if (ProcessStartInfoWrapper.RedirectStandardInput)
{
StreamWriter.Flush();
StreamWriter.Close();
}
}
catch
{
}
try
{
if (!HasExitedCheck())
{
Process.CloseMainWindow();
}
}
catch
{
}
try
{
Process.Close();
Process.WaitForExit(10000);
}
catch
{
}
try
{
Process.Dispose();
}
catch
{
}
try
{
if (!HasExitedCheck())
{
Process.Kill();
}
}
catch
{
}
Process.Dispose();
ProcessStartInfoWrapper.Dispose();
try
{
//small theoretical risk of another process starting with same id, but this does make sure unmanaged processes close!
Process.GetProcessById(processId).Kill();
}
catch
{
}
}
}
private bool HasExitedCheck()
{
//unmanaged processes might not have .HasExited, so check here and default to false
bool hasExited = false;
try
{
hasExited = Process.HasExited;
}
catch
{
}
return hasExited;
// ReSharper restore EmptyGeneralCatchClause
}
private void WaitForListToContainText(IList<string> list, string expectedText, int waitTimeMilliSeconds)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
while (stopwatch.ElapsedMilliseconds <= waitTimeMilliSeconds)
{
if (SyncOnTextInList(list, expectedText, false)) return;
Thread.Sleep(20);
}
SyncOnTextInList(list, expectedText, true);
}
private bool SyncOnTextInList(IList<string> list, string expectedText, bool throwExceptions)
{
bool sync = false;
lock (list)
{
try
{
string[] shadowList = SetShadowList(list);
if (shadowList.Any(line => line.Trim().Contains(expectedText.Trim())))
//if (shadowList.Any(line => line != null && line.Trim().Contains(expectedText.Trim())))
{
sync = true;
}
}
catch (Exception)
{
if (throwExceptions)
{
throw;
}
}
}
return sync;
}
private static string[] SetShadowList(ICollection<string> list)
{
var shadowList = new string[list.Count];
list.CopyTo(shadowList, 0);
shadowList = shadowList.Select(x => x ?? "").ToArray();
return shadowList;
}
}