3

我有一个 Windows 窗体应用程序,它本身会启动不同的线程来完成不同类型的工作。有时,所有线程(包括 UI 线程)都被冻结,我的应用程序变得无响应。我认为这可能是与垃圾收集器相关的问题,因为 GC 将暂时冻结所有托管线程。为了验证只是托管线程被冻结,我启动了一个非托管线程,它每秒写入一个带有时间戳的“心跳”文件,并且它不受影响(即它仍然运行):

public delegate void ThreadProc();

[DllImport("UnmanagedTest.dll", EntryPoint = "MyUnmanagedFunction")]
public static extern void MyUnmanagedFunction();

[DllImport("kernel32")]
public static extern IntPtr CreateThread(
    IntPtr lpThreadAttributes,
    uint dwStackSize,
    IntPtr lpStartAddress,
    IntPtr lpParameter,
    uint dwCreationFlags,
    out uint dwThreadId);    

uint threadId;
ThreadProc proc = new ThreadProc(MyUnmanagedFunction);
IntPtr functionPointer = Marshal.GetFunctionPointerForDelegate(proc);
IntPtr threadHandle = CreateThread(IntPtr.Zero, 0, functionPointer, IntPtr.Zero, 0, out threadId);

我的问题是:如何模拟这种情况,所有托管线程都被挂起但非托管线程继续旋转?

我的第一次刺

private void button1_Click(object sender, EventArgs e) {
    Thread t = new Thread(new ThreadStart(delegate {
        new Hanger();
        GC.Collect(2, GCCollectionMode.Forced);
    }));
    t.Start();
}
class Hanger{
    private int[] m_Integers = new int[10000000];
    public Hanger() { }
    ~Hanger() { Console.WriteLine("About to hang...");

    //This doesn't reproduce the desired behavior
    //while (true) ;

    //Neither does this
    //Thread.Sleep(System.Threading.Timeout.Infinite); 
    }
}

提前致谢!!

4

4 回答 4

1

终结器与“正常”线程执行同时执行。我们通常说 GC 运行终结器,但更真实的情况是 GC 检测哪些实例具有应该运行的终结器,并将它们存储在专用队列中。一个(隐藏的)线程从队列中获取实例并运行终结器。需要这种异步性,例如因为终结器可能自己分配内存并可能触发 GC。终结器必须是异步的还有其他充分的理由。

底线是,您无法更改~Hanger()虚拟机在 GC 暂停期间所做的事情,因为此时实际运行的线程~Hanger()也会暂停。

于 2010-03-27T17:20:21.820 回答
0

我意识到这并不能回答您的问题,但我怀疑您的代码中存在死锁,而不是奇怪的 GC 问题。

我建议检查您的代码是否存在死锁,尤其是间接情况,例如Control.Invoke从后台线程进行 UI 更新时的调用。确保在调用 an 时没有持有锁Invoke- 这可能会导致意外死锁(就好像预期会出现任何死锁 :))

于 2010-03-27T18:56:29.503 回答
0

这个问题实际上源于垃圾收集器。用 WinDbg 调试和分析内存转储多天后,我们意识到存在死锁情况,但由 GC 并发收集引起。将 GC 更改为非并发收集解决了我们的问题。

于 2010-04-17T15:54:41.270 回答
0

支持 Marek 的回答,这似乎很像您正在使用的并发模型的设计问题。作为一个设计问题,这是您无法通过测试有效解决的问题。

我的建议是仔细考虑您正在使用的并发模型,并相应地更正设计。首先查看死锁的必要条件,例如:

  1. 你有什么相互排斥的?
  2. 您的流程(已经在使用某些资源)需要哪些额外资源?
  3. 哪些资源需要显式释放是使用它们的进程?

考虑到这些,如果您有循环资源分配结构,您正在调查可能的死锁情况。

于 2010-04-17T16:09:37.590 回答