Skip to main content
 首页 » 编程设计

c#之当工作线程和UI线程调用同一方法(包括调用ui控件)时出现死锁

2024年01月21日25zlslch

这是我的代码描述的问题:

public partial class Form1 : Form 
{ 
    private readonly  object lockObject = new object(); 
    public Form1() 
    { 
        InitializeComponent(); 
    } 
 
    private void btnWorkerThread_Click(object sender, EventArgs e) 
    { 
        Task.Factory.StartNew(() => SomeLongRunningThread()); 
    } 
 
    private void SomeLongRunningThread() 
    { 
        lock (lockObject) 
        { 
            Thread.Sleep(3000); 
            if (txtResult.InvokeRequired) 
            { 
                Thread.Sleep(3000); 
                txtResult.Invoke((MethodInvoker) delegate { txtResult.Text = DateTime.Now.ToShortTimeString(); }); 
            } 
            else 
            { 
                Thread.Sleep(3000); 
                txtResult.Text = DateTime.Now.ToShortTimeString(); 
            } 
        } 
 
    } 
 
    private void btnUIThread_Click(object sender, EventArgs e) 
    { 
        SomeLongRunningThread(); 
    } 
} 

当工作线程启动,然后btnUIThread单击的死锁发生:

似乎在txtResult.InvokeRequried上发生了死锁:
  • 工作线程将控制权传递给ui线程
  • 由于ui线程已轮到,它既更新txtResult并尝试启动btnUIThread单击。
  • 死锁发生在行txtResult.Invoke((MethodInvoker) delegate { txtResult.Text = DateTime.Now.ToShortTimeString(); });
  • 上

    如果我错了,请纠正我。

    问题是如何处理死锁?

    编辑:在获得来自同仁的宝贵答复后,我的实际项目比预期的要复杂得多,lock块具有更多的代码,我必须保证它们一次可以由一个线程执行。

    请您参考如下方法:

    为了避免死锁,您应该使用不同的lock。锁定所有线程代码没有意义。
    此外,此锁(lockobject)不是必需的,因为在示例SomeAction()中已经将其同步以在主/UI线程中执行。

    private void SomeLongRunningThread() 
    { 
     
        Thread.Sleep(3000); 
        if (txtResult.InvokeRequired) 
        { 
            Thread.Sleep(3000); 
            txtResult.Invoke((MethodInvoker) delegate { SomeAction }); 
        } 
        else 
        { 
            Thread.Sleep(3000); 
            SomeAction(); 
        } 
     
     
    } 
     
    private void SomeAction(){ 
        // This lock is not needed as long this method is only called from SomeLongRunningThread() 
        //lock (lockObject) 
        //{ 
            txtResult.Text = DateTime.Now.ToShortTimeString(); 
        //} 
    }