Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何确定在我的应用程序退出时谁拥有仍在运行的工作线程?_C#_Wpf_Multithreading_Visual Studio 2010_.net 4.0 - Fatal编程技术网

C# 如何确定在我的应用程序退出时谁拥有仍在运行的工作线程?

C# 如何确定在我的应用程序退出时谁拥有仍在运行的工作线程?,c#,wpf,multithreading,visual-studio-2010,.net-4.0,C#,Wpf,Multithreading,Visual Studio 2010,.net 4.0,升级到VS2010后不久,我的应用程序不会完全关闭。如果我关闭应用程序,然后在IDE中单击暂停,我会看到: 问题是,没有上下文。调用堆栈只显示[外部代码],这没有太大帮助 以下是我迄今为止为缩小问题范围所做的工作: 删除所有无关的插件,以尽量减少启动的工作线程数 在我的代码中创建工作线程的任何地方设置断点(和委托+BeginInvoke,因为我认为它们在调试器中标记为“工作线程”)。没有人中枪 为所有线程设置IsBackground=true 虽然我可以做下一个暴力步骤,也就是将代码回滚到

升级到VS2010后不久,我的应用程序不会完全关闭。如果我关闭应用程序,然后在IDE中单击暂停,我会看到:

问题是,没有上下文。调用堆栈只显示[外部代码],这没有太大帮助

以下是我迄今为止为缩小问题范围所做的工作:

  • 删除所有无关的插件,以尽量减少启动的工作线程数
  • 在我的代码中创建工作线程的任何地方设置断点(和委托+BeginInvoke,因为我认为它们在调试器中标记为“工作线程”)。没有人中枪
  • 为所有线程设置IsBackground=true
虽然我可以做下一个暴力步骤,也就是将代码回滚到没有发生这种情况的地方,然后查看所有更改日志,但这并不是非常有效。鉴于调试器提供的信息明显不足,有人能推荐一种更好的方法来解决这个问题吗

我唯一能想到的其他事情包括:

  • 阅读WinDbg,并尝试在线程启动时使用它停止。至少,我认为这是可能的……:)
  • 注释掉大量代码块,直到应用程序正确关闭,然后开始取消注释,直到应用程序无法正常关闭
更新

也许这些信息会有用。我决定使用WinDbg并附加到我的应用程序。然后我关闭它,切换到线程0并转储堆栈内容。以下是我所拥有的:

ThreadCount:      6
UnstartedThread:  0
BackgroundThread: 1
PendingThread:    0
DeadThread:       4
Hosted Runtime:   no
                                   PreEmptive   GC Alloc                Lock
       ID  OSID ThreadOBJ    State GC           Context       Domain   Count APT Exception
   0    1  1c70 005a65c8      6020 Enabled  02dac6e0:02dad7f8 005a03c0     0 STA
   2    2  1b20 005b1980      b220 Enabled  00000000:00000000 005a03c0     0 MTA (Finalizer)
XXXX    3       08504048     19820 Enabled  00000000:00000000 005a03c0     0 Ukn
XXXX    4       08504540     19820 Enabled  00000000:00000000 005a03c0     0 Ukn
XXXX    5       08516a90     19820 Enabled  00000000:00000000 005a03c0     0 Ukn
XXXX    6       08517260     19820 Enabled  00000000:00000000 005a03c0     0 Ukn
0:008> ~0s
eax=c0674960 ebx=00000000 ecx=00000000 edx=00000000 esi=0040f320 edi=005a65c8
eip=76c37e47 esp=0040f23c ebp=0040f258 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
USER32!NtUserGetMessage+0x15:
76c37e47 83c404          add     esp,4
0:000> !clrstack
OS Thread Id: 0x1c70 (0)
Child SP IP       Call Site
0040f274 76c37e47 [InlinedCallFrame: 0040f274] 
0040f270 6baa8976 DomainBoundILStubClass.IL_STUB_PInvoke(System.Windows.Interop.MSG ByRef, System.Runtime.InteropServices.HandleRef, Int32, Int32)*** WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v4.0.30319_32\WindowsBase\d17606e813f01376bd0def23726ecc62\WindowsBase.ni.dll

0040f274 6ba924c5 [InlinedCallFrame: 0040f274] MS.Win32.UnsafeNativeMethods.IntGetMessageW(System.Windows.Interop.MSG ByRef, System.Runtime.InteropServices.HandleRef, Int32, Int32)
0040f2c4 6ba924c5 MS.Win32.UnsafeNativeMethods.GetMessageW(System.Windows.Interop.MSG ByRef, System.Runtime.InteropServices.HandleRef, Int32, Int32)
0040f2dc 6ba8e5f8 System.Windows.Threading.Dispatcher.GetMessage(System.Windows.Interop.MSG ByRef, IntPtr, Int32, Int32)
0040f318 6ba8d579 System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame)
0040f368 6ba8d2a1 System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame)
0040f374 6ba7fba0 System.Windows.Threading.Dispatcher.Run()
0040f380 62e6ccbb System.Windows.Application.RunDispatcher(System.Object)*** WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v4.0.30319_32\PresentationFramewo#\7f91eecda3ff7ce478146b6458580c98\PresentationFramework.ni.dll

0040f38c 62e6c8ff System.Windows.Application.RunInternal(System.Windows.Window)
0040f3b0 62e6c682 System.Windows.Application.Run(System.Windows.Window)
0040f3c0 62e6c30b System.Windows.Application.Run()
0040f3cc 001f00bc MyApplication.App.Main() [C:\code\trunk\MyApplication\obj\Debug\GeneratedInternalTypeHelper.g.cs @ 24]
0040f608 66c421db [GCFrame: 0040f608]
编辑--不确定这是否有帮助,但主线程的调用堆栈如下所示:

    [Managed to Native Transition]  
>   WindowsBase.dll!MS.Win32.UnsafeNativeMethods.GetMessageW(ref System.Windows.Interop.MSG msg, System.Runtime.InteropServices.HandleRef hWnd, int uMsgFilterMin, int uMsgFilterMax) + 0x15 bytes  
    WindowsBase.dll!System.Windows.Threading.Dispatcher.GetMessage(ref System.Windows.Interop.MSG msg, System.IntPtr hwnd, int minMessage, int maxMessage) + 0x48 bytes 
    WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame frame = {System.Windows.Threading.DispatcherFrame}) + 0x85 bytes 
    WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame frame) + 0x49 bytes  
    WindowsBase.dll!System.Windows.Threading.Dispatcher.Run() + 0x4c bytes  
    PresentationFramework.dll!System.Windows.Application.RunDispatcher(object ignore) + 0x17 bytes  
    PresentationFramework.dll!System.Windows.Application.RunInternal(System.Windows.Window window) + 0x6f bytes 
    PresentationFramework.dll!System.Windows.Application.Run(System.Windows.Window window) + 0x26 bytes 
    PresentationFramework.dll!System.Windows.Application.Run() + 0x1b bytes 

我对它进行了搜索,发现了一些与WPF GUI挂起相关的帖子,也许这会给我更多的线索。

如果您正在创建工作线程(而不是池线程),在创建时将其设置为描述性。

在所有代码中添加日志记录,以记录方法和线程ID。您可以使用regex替换将其放在每个方法的开头。然后运行应用程序并关闭。查看哪些日志消息与未关闭的工作线程具有相同的线程id。

您看到的工作线程id为0。这是一个框架线程,并且是预期的-它不是程序“生成”的线程。如果您连接到任何.Net进程,您将看到这一点。我不确定它是哪个框架线程-肯定不是终结器线程,因为它从来都不是线程0。也许是JIT线程

更有趣的是你的主线,因为它看起来是挂着的。我将集中精力调试您的主线程,以彻底解决此问题。它是否已经从一个窗口关闭的事件处理程序中死锁,等待一些永远不会发生的事情,例如

更新

在读取添加到问题中的主线程的堆栈跟踪之后,运行一个测试来查明主线程是否已暂停,或者它是否只是在等待消息(并且它正在等待从未收到或从未发送的WM_关闭)时处于空闲状态

下面的代码可用于手动向应用程序发送WM_CLOSE消息。只需等待程序关闭后挂起,然后运行代码。将进程名称替换为您自己的名称

更新2

好的,看起来主线程已经挂起,因为它没有处理WM_关闭或WM_退出消息

请尝试,使最小的应用程序,可以复制问题和张贴代码

示例WM\U关闭\WM\U退出应用程序

internal class Program
{
    private const int WM_QUIT = 0x0012;
    private const int WM_CLOSE = 0x0010;

    [DllImport("user32.dll")]
    private static extern bool PostMessage(int hhwnd, uint msg, IntPtr wParam, IntPtr lParam);

    private static void Main()
    {
        Process p = GetProcess("Your process name - no '.exe' required");

        CloseMainWindow(p);
    }

    private static Process GetProcess(string name)
    {
        List<Process> processes = Process.GetProcessesByName(name).ToList();

        if (processes.Count != 1)
        {
            throw new Exception(
              "Expected 1 process with name '" + name +
              "' but found " + processes.Count + ".");
        }

        return processes[0];
    }

    private static void CloseMainWindow(Process p)
    {
        PostMessage(p, WM_CLOSE, "close");
    }

    private static void QuitApplication(Process p)
    {
        PostMessage(p, WM_QUIT, "quit");
    }

    private static void PostMessage(Process p, uint message, string name)
    {
        Console.WriteLine("Posting {0} message to '{1}'...", name, p.ProcessName);

        bool succeeded = PostMessage(p.MainWindowHandle.ToInt32(), message, IntPtr.Zero, IntPtr.Zero);

        Console.WriteLine("Posted {0} message to '{1}' (succeeded:{2}).", name, p.ProcessName, succeeded);
    }
} 
内部类程序
{
私有常量int WM_QUIT=0x0012;
私有常量int WM_CLOSE=0x0010;
[DllImport(“user32.dll”)]
私有静态外部bool PostMessage(inthhwnd、uint msg、IntPtr wParam、IntPtr lParam);
私有静态void Main()
{
进程p=GetProcess(“您的进程名称-不需要“.exe”);
关闭主窗口(p);
}
私有静态进程GetProcess(字符串名称)
{
List processs=Process.GetProcessesByName(name.ToList();
if(processs.Count!=1)
{
抛出新异常(
“应为1个名为“”的进程+名称”+
“'但找到“+进程数+”;
}
返回进程[0];
}
私有静态void closeMain窗口(进程p)
{
PostMessage(p,WM_CLOSE,“CLOSE”);
}
专用静态应用程序(进程p)
{
PostMessage(p,WM_QUIT,“QUIT”);
}
私有静态void PostMessage(进程p、uint消息、字符串名称)
{
WriteLine(“将{0}消息发布到{1}'…”,name,p.ProcessName);
bool succeed=PostMessage(p.MainWindowHandle.ToInt32(),message,IntPtr.Zero,IntPtr.Zero);
WriteLine(“将{0}消息发布到{1}”(成功:{2})。”,name,p.ProcessName,succeed);
}
} 

将以下处理程序添加到应用程序在单独线程中创建的每个窗口中:

win.Closed += (o, e) => win.Dispatcher.InvokeShutdown();
如果主线程挂起,请在
MainWindow.Closed
中调用
win.Dispatcher.InvokeShutdown()
-这将自动关闭在主线程中创建的所有其他窗口

如果没有此处理程序,我的应用程序在退出时也会挂起以下代码:

void Worker() {
    var win = new Window();
    // win.Closed += onWindowClose ?? ((o, e) => editor.Dispatcher.InvokeShutdown());
    editor.Show();
    System.Windows.Threading.Dispatcher.Run();
}

我终于解决了这个问题。我有一个控件,它被MEF
Import
ed,但实际上从未调用过。我认为MEF实例化了它,尽管它没有在任何地方被引用(我假设在请求资源之前不会创建,但显然我错了)。我通过使用惰性实例化修复了这个问题,现在它可以工作了。这一次真让我抓狂,但谢谢大家的帮助。我在调试这个问题时学到了很多。

你的主线程在做什么?只是坐在那里等着有人点击按钮。@Dave我是说它在做什么