You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Framework 4.8 WinForms两线程死锁原因排查求助

WinForms应用死锁排查问题

环境信息

  • 软件/技术栈:基于.NET Framework 4.8的WinForms应用
  • 构建配置:Debug Build
  • 死锁同步结构:类私有作用域对象实现的Monitor
  • 死锁场景:工作线程(Thread #2)与UI线程发生死锁

更新1:清楚这是糟糕的设计,会进行修复,已简化示例以便明确死锁位置。本次发帖核心是排查锁未释放导致死锁的原因。
更新2:经验教训:不要混合同步与异步操作。

问题代码

public class Form
{
    private static SomeSharedObject sharedObj = new SomeSharedObject();
    
    Init() // called once
    {
        // UI thread starts initialization
        
        // register for notifications (later Thread #2, background worker thread, will callback Device_Attach causing a dead lock between itself and UI thread)
        sharedObj.Attach += new EventHandler<USBConnectionEventArgs>(Device_Attach);
        
        
        // kick off background worker task
        bw.RunWorkerAsync(); // UI thread spawns the 2nd thread (Thread #2) that will dead lock with the UI thread
        // UI thread continues to run ...
        
        // UI thread calls a method on a shared static instance (between UI thread and Thread #2) to access some property
        var devices = sharedObj.ConnectedDevices; // DEAD LOCKS! See pseudo implementation of SomeSharedObject
    }
    
    private void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        sharedObj.ReadState(); // Thread #2 reading the state
    }
    
    void Device_Attach(object sender, USBConnectionEventArgs e)
    {
        _RefreshHwDeviceList(); // Still Thread #2, but now refreshing the UI
    }
    
    delegate void RefreshHwDeviceListCallBack();
    private void _RefreshHwDeviceList()
    {
        // Thread #2 enters here to update the UI
        // Since we're here on background worker thread and need to update UI, switch to UI thread.
        // NOTE: Bam, we're in a dead lock (at line HwDeviceList.Invoke())! UI thread is still blocked in SomeSharedObject.ConnectedDevices (on the _accessLock), but
        // that doesn't make sense since Thread #2 released the _accessLock before calling Attach callback (why is this lock still held by Thread #2)
        // How do I know?
        //  When I break in VS and open threads watch window, VS clearly says that the main UI thread is blocked on Thread #2 at the location
        // of the _accessLock in SomeSharedObject.ConnectedDevices property.
        if (HwDeviceList.InvokeRequired) 
        {
            var callback = new RefreshHwDeviceListCallBack(_RefreshHwDeviceList);
            HwDeviceList.Invoke(callback, new object[] { });
        }
        else
        {
            // update UI on UI thread
        }
    }
}

public class SomeSharedObject
{
    private readonly object _accessLock = new object();
    public event EventHandler<USBConnectionEventArgs> Attach;
    
    public IEnumerable<IDevice> ConnectedDevices
    {
        get
        {
            lock (_accessLock) // NOTE: This line is where the UI thread will wait indefinitely wait for Thread #2, but Thread #2 should of released this lock (see ReadState())!
            {
                
                return _deviceList
                    .Where(x => x.IsConnected ||
                            ((x as IUSBDevice)?.IsAttached ?? false))
                    .ToArray();
            }
        }
    }
    
    public void ReadState()
    {
        var attachingDevice = e.Device;
        lock (_accessLock) // Thread #2 grabs the lock first, so UI thread is blocked, okay that's fine as long as at the end of its scope the lock is released
        {
            // read some state
        } //NOTE: release the lock here before raising the event below so we don't DEAD lock the UI thread (but the lock is not released, why????)
        
        // Thread #2 now calls back to the Form's handler
        if (Attach != null)
        {
            Attach(this, e);
        }
    }
}

内容的提问来源于stack exchange,提问作者ActiveX

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 08:44:52