【问题标题】:Killing multiple processes that were started from nested threads... C#杀死从嵌套线程启动的多个进程... C#
【发布时间】:2012-04-20 19:10:35
【问题描述】:

我是编程新手。我有一个启动线程的表单应用程序。从那里启动了 4 个新线程。这些线程中的每一个都执行一系列命令行进程,如下所示:

ProcessStartInfo startInfo = new ProcessStartInfo();
        startInfo.WorkingDirectory ="C:\\BLA\\bin_windows";
        startInfo.UseShellExecute = false;
        startInfo.RedirectStandardOutput = true;
        startInfo.CreateNoWindow = true;

            startInfo.FileName = "SomeProcess"
            Process p = Process.Start(startInfo);
        p.WaitForExit();

当表单应用程序关闭时,它会中止第一个线程(不是 4 个单独的线程)。 现在我的问题是当我关闭表单时如何强制进程“p”退出? 我尝试了以下方法:

    foreach (Process p in System.Diagnostics.Process.GetProcessesByName("SomeProcess"))
    {
        try
        {
            p.Kill();
            p.WaitForExit(); // possibly with a timeout
        }
        catch
        { continue; }
    } 

但是,这种方法对我来说似乎有点残忍,而且并不总是很好用......有没有一种方法可以让我只识别我自己启动的进程然后终止它们? 任何建议都非常感谢。 谢谢

【问题讨论】:

  • 拥有你启动的所有进程的某种全局列表怎么样?
  • @dwrd -- 听起来不错 -- 但我不知道该怎么做……你能解释更多吗?谢谢!

标签: c# multithreading process nested kill


【解决方案1】:

您几乎无法控制已运行的进程。杀死他们是一种方式。如果进程是一个窗口应用程序(即有一个窗口),您可以尝试向它发送WM_CLOSE 消息,这相当于单击窗口上的关闭按钮。同样,应用程序必须有一个可见或隐藏的窗口,因此它不能在每个应用程序上运行。大多数应用程序都有窗口,即使不可见。

const uint WM_CLOSE = 0x10;

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd, uint uMsg, int wParam, int lParam);

Process p = Process.GetProcessesByName("notepad").FirstOrDefault();
if(p != null)
{
    IntPtr hWnd = p.MainWindowHandle;
    SendMessage(hWnd, WM_CLOSE, 0, 0);
}

如果你想使用我给你的方法,要只杀死/关闭你产生的进程,只需保留它们的Process 对象或至少p.MainWindowHandle。为此,在您的班级中有一个 ConcurrentBag<Process>(或 ConcurrentBag<IntPtr>)类型的公共属性。它已经是线程安全的。

编辑

正如有人指出的那样,您可以这样做来关闭进程的主窗口:

p.CloseMainWindow()

【讨论】:

  • 谢谢 - 因为它们是命令行程序,我认为它们没有 Windows?!或者?此外,最好只杀死表单应用程序启动的内容。
  • @timkado 它也应该适用于控制台应用程序,因为它们确实有窗口。要仅杀死您生成的进程,请保留它们的 Process 对象或至少 p.MainWindowHandle
【解决方案2】:

如果您的程序不应该一次运行两次,您可以在单例上使用某种进程管理器:

internal sealed class ProcessManager
{
    private readonly IList<Process> processes;

    #region Singleton

    private static readonly object locker = new object();
    private static volatile ProcessManager instance;

    private ProcessManager()
    {
        processes = new List<Process>();
    }

    public static ProcessManager Instance
    {
        get
        {
            if (instance == null)
            {
                lock (locker)
                {
                    if (instance == null)
                    {
                        instance = new ProcessManager();
                    }
                }
            }

            return instance;
        }
    }

    #endregion

    public void AddProcess(Process process)
    {
        lock(processes)
        {
            processes.Add(process);
        }
    }

    public void TerminateAll()
    {
        lock(processes)
        {
            foreach (Process p in processes)
            {
                try
                {
                    p.Kill();
                    p.WaitForExit(); // possibly with a timeout
                }
                catch
                {
                     continue;
                }
            }
        }
    }
}

用法:

ProcessStartInfo startInfo = new ProcessStartInfo();
    startInfo.WorkingDirectory ="C:\\BLA\\bin_windows";
    startInfo.UseShellExecute = false;
    startInfo.RedirectStandardOutput = true;
    startInfo.CreateNoWindow = true;

        startInfo.FileName = "SomeProcess"
        Process p = Process.Start(startInfo);
        ProcessManager.Instance.AddProcess(p);
    p.WaitForExit();

如果你不希望你的程序中有静态的东西(例如,你可以有一些它的实例),你可以使用这个类,但没有单例并将它的单个实例提供给每个线程。

【讨论】:

  • 或者你可以用public static ConcurrentBag&lt;Process&gt; processes = new ConcurrentBag&lt;Process&gt;();替换几乎所有的代码
  • 呵呵,不知道 ConcurrentBag 类 :) 好记
  • 您可以在许多 Nevada 酒吧以非常合理的价格购买 ConcurrentBags,但在第五个大型 JD 之后,您最好排队。
【解决方案3】:

如果您想关闭流程,则无需 P/Invoke 并发送 WM_CLOSE 消息,只需在您的 Process 实例上调用 CloseMainWindow() 方法(它将为您发送 WM_CLOSE)。然后,您可以使用Close() 方法跟进它以发布您的本地视图。

跟踪您已启动的流程也相当容易。

public static ConcurrentBag<Process> processes = new ConcurrentBag<Process>();

在创建过程时存储它们。

Process process = ... //Create your process
processes.Add(process);

然后循环并关闭它们。

foreach (var process in processes)
{
    if (!process.HasExited)
    {
        process.CloseMainWindow();
        process.Close();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-22
    相关资源
    最近更新 更多