当我从c#库中调用它以清除WerFault.exe进程时,(讽刺地)挂起了Taskkill
我正在尝试使用taskkill来关闭从nunit运行的负载测试中产生的WerFault进程。只要测试启动的外部进程失败,就会创建WerFault.exe,因为它无法连接到其使用的服务,或者因为内存不足。暂时原谅这是一个将负载放入系统的非常复杂的方式,我宁愿与我直接加载的服务进行交互,这是暂时结束的手段而不是长期解决方案。
这些进程是非托管的c ++ exes所以我不能使用Process.GetProcessesByName(processName)然后对结果进行process.kill。
我在下面的示例中添加了一个潜在的修复程序,但是直到后来我才能测试这个,因为我需要运行大量的迭代来强制使用WerFault.exe。欢迎任何建议!
这是我到目前为止所得到的: -
processName.KillProcessesByName(真);
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;
}
}
答案 0 :(得分:0)
感谢您的回复。我用过的样本 http://www.codeproject.com/Articles/18146/How-To-Almost-Everything-In-WMI-via-C-Part-Proce 处理进程终止,并找到一些其他有用的方法来查询对非托管代码更可靠地工作的进程。这是一种更好的杀死进程的方法,而不是必须启动另一个进程(或两个或三个)来完成这项工作。
所以&#34;为什么taskkill会挂?&#34;,从我的实验中看,这看起来像是一个负载问题。
刚刚意识到我可以直接启动taskkill,而不是从cmd.exe启动,但至少我已经学会了如何从.Net调用WMI