【问题标题】:About Async Tasks and Disposal关于异步任务和处置
【发布时间】:2013-05-14 20:01:26
【问题描述】:

在我的MainWindow 中,我有一个按钮可用于打开Process(本机OpenProcess 调用)并对其内存进行一些检查,但Click 调用的方法是异步的:

<Button Content="Attach" Click="OnClickAttach"/>

private async void OnClickAttach(Object sender, RoutedEventArgs e)
{
    AttachmentResult result = await m_ViewModel.Attach();

    switch (result)
        // Different MessageBox depending on the result.
}

现在,让我们看看代码的ViewModel 部分...

// MemoryProcess class is just a wrapper for Process' handle and memory regions.
private MemoryProcess m_MemoryProcess;

public async Task<AttachmentResult> Attach()
{
    AttachmentResult result = AttachmentResult.Success;
    MemoryProcess memoryProcess = NativeMethods.OpenProcess(m_SelectedBrowserInstance.Process);

    if (memoryProcess == null)
        result = AttachmentResult.FailProcessNotOpened;
    else
    {
        Boolean check1 = false;
        Boolean check2 = false;

        foreach (MemoryRegion region in memoryProcess)
        {
            // I perform checks on Process' memory regions and I eventually change the value of check1 or check2...
            await Task.Delay(1);
        }

        if (!check1 && !check2)
        {
            NativeMethods.CloseHandle(memoryProcess.Handle);
            result = AttachmentResult.FailProcessNotValid;
        }
        else
        {
            // I keep the Process opened for further use. I save it to a private variable.
            m_MemoryProcess = memoryProcess;
            m_MemoryProcess.Check1 = check1;
            m_MemoryProcess.Check2 = check2;
        }
    }

    return result;
}

现在……问题来了。当用户关闭应用程序时,如果打开了Process,我必须正确关闭它的句柄。所以在我的MainWindow 我有以下代码:

protected override void OnClosing(CancelEventArgs e)
{
    m_ViewModel.Detach();
    base.OnClosing(e);
}

在我的ViewModel 中,我有以下代码:

public void Detach()
{
    if (m_MemoryProcess != null)
    {
        if (m_MemoryProcess.Check1)
            // Do something...

        if (m_MemoryProcess.Check2)
            // Do something...

        NativeMethods.CloseHandle(m_MemoryProcess.Handle);
        m_MemoryProcess = null;
    }
}

Attach() 方法可能需要很长时间,有时超过 2 分钟。我需要找到以下问题的解决方案:

  • 如果用户在Attach() 方法运行时关闭应用程序,并且在memoryProcess 保存到私有变量之前,Process 句柄将不会关闭。
  • 如果我在 Attach() 方法的开头将 MemoryProcess 实例保存到私有变量中,如果用户在 Attach() 方法正在处理时关闭应用程序,则用户有可能获得 NullReferenceException它的 foreach 循环。
  • 我绝对不想让用户在让他关闭应用程序之前等待Attach() 方法完成。太可怕了。

我该怎么做?

【问题讨论】:

  • 当他们关闭应用程序时怎么样,如果 asyc 调用没有完成......只需隐藏窗口直到完成,然后在完成后关闭实际应用程序
  • 这也很奇怪,因为该方法占用大量 CPU 资源,而且如果应用程序在完成后将被关闭……那么,这有什么意义呢?!最好的办法是完全停止它......这就是我想要做的。
  • 您应该使用 SafeWin32Handle 而不是 IntPtr,这样您就可以处置处理程序而不是关闭它(即如果您忘记了 GC 将处置它。例如:public static extern SafeWin32Handle OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
  • 是的,但问题没有改变。我总是必须在需要时关闭或处理句柄,并且必须保持打开状态,直到用户关闭应用程序。
  • 不清楚您在担心什么。 Windows 会自动清理任何未被应用关闭的句柄。

标签: c# .net task-parallel-library async-await dispose


【解决方案1】:

IMO,如果您没有明确和专门针对创建单独的分离/独立进程,例如,通过:

  • 使用 PInvoke.CreateProcess
  • 使用

    (new System.Management.ManagementClass("Win32_ProcessStartup"))
    .Properties["CreateFlags"].Value = 8;
    
  • 或在应用关闭时通过单独的 shell 脚本或其他在应用关闭后仍要运行的进程启动子进程来保持子进程处于活动状态;

  • 使用CreateRemoteThread在另一个独立进程中创建新线程
  • 等。

或者发现已经独立运行的进程,你不需要和probably should not "close" or dispose spawned by app processes。 Windows(操作系统)将关闭任何由应用程序进程产生的未关闭。

另外,我相信一旦应用程序开始退出或关闭,就不可能在应用程序中执行任何代码。

PS(题外话):
我什至没有看到你关闭 (really one should kill) 或在你的代码中处理你的进程......

【讨论】:

    猜你喜欢
    • 2020-03-12
    • 1970-01-01
    • 1970-01-01
    • 2014-12-10
    • 1970-01-01
    • 2011-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多