-1

当我从 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;
    }
}
4

1 回答 1

0

感谢您的回复。我使用来自http://www.codeproject.com/Articles/18146/How-To-Almost-Everything-In-WMI-via-C-Part-Proce的示例 来处理进程杀戮,并找到了一些其他有用的方法那里用于查询对非托管代码更可靠地工作的进程。这是杀死一个进程的更好方法,而不是必须启动另一个进程(或两个或三个)来完成这项工作。

所以“为什么taskkill挂起?”,从我的实验来看,它看起来像是一个负载问题。

刚刚意识到我可以直接启动 taskkill 这可能会起作用,而不是从 cmd.exe 启动,但至少我今天学会了如何从 .Net 调用 WMI

于 2014-10-16T16:42:59.910 回答