如何模拟此应用程序挂起方案?

时间:2010-03-26 19:36:18

标签: .net multithreading garbage-collection hang

我有一个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 个答案:

答案 0 :(得分:1)

终结器与“正常”线程执行同时执行。我们通常说GC运行终结器,但GC更准确地检测哪些实例具有应该运行的终结器,并将它们存储在专用队列中。 (隐藏)线程从队列中获取实例并运行终结器。需要这种异步,例如,因为终结器本身可能会分配内存并可能触发GC。还有其他good reasons为什么终结器必然是异步的。

一句话是,您无法从~Hanger()更改VM在GC暂停期间执行的操作,因为实际运行~Hanger()的线程此时也会暂停。

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

问题DID实际上源于垃圾收集器。经过多天使用WinDbg调试和分析内存转储,我们意识到存在死锁情况,但同时由GC收集引起。 Changing the GC to collect non-concurrently解决了我们的问题。

答案 3 :(得分:0)

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

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

  1. 你有什么相互排斥?
  2. 您的流程(已使用某些资源)需要哪些额外资源?
  3. 哪些资源需要明确发布才是使用它们的过程?
  4. 考虑到这些因素,如果您有循环资源分配结构,那么您正在研究可能出现的死锁情况。