锁内的UI线程调用的方法从() [英] Invoking Method on UI thread from within a Lock()

查看:78
本文介绍了锁内的UI线程调用的方法从()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两种方法,治法&安培; 方法b 方法b 必须在UI线程上运行。我需要他们跑一前一后,而不允许 MethodC 来中间他们跑了。

I have two methods, MethodA & MethodB. MethodB has to run on the UI thread. I need them to run one after the other without allowing MethodC to run betwixt them.

MethodC 当用户点击一个可爱的小按钮被调用。

MethodC is called when a user clicks on a lovely little button.

我做了什么,以确保这是把锁定周围的代码这样的:

What I did to ensure this is put a Lock around the code thus:

 Lock (MyLock)
 {
   MethodA(param1, param2);

   MyDelegate del = new MyDelegate(MethodB);
   if (this.IsHandleCreated) this.Invoke(del);
 }

和对 MethodC

public void MethodC()
 Lock (MyLock)
 {
   Do bewildering stuff.....
 }

但问题是,我被卡住。它看起来像我的代码是怎么回事陷入僵持。

Problem is I'm getting stuck. It looks like my code's going into a deadlock.

当我看到我看到的按钮,点击调用的代码是停留在螺纹锁(MyLock) MethodC 和我的其他线程似乎停留在 this.Invoke(DEL)

When I look at the threads I see that the code called by the button click is stuck at Lock (MyLock) in MethodC and my other thread seems stuck at this.Invoke(del).

我读过它的危险,从内锁定调用一个方法,但因为我是一个谁写的代码,而这似乎即使只有一个 Thread.sleep代码我想,这不是说的让我陷入麻烦的代码。

I've read it's dangerous to invoke a method from within a Lock but since I'm the one who wrote the code there and this seems to happen even with just a Thread.Sleep I figure it's not the code that's getting me into trouble.

为什么会被调用的方法停止工作?
是它可能等待在 methodC 锁才回到原来的锁它从调用被释放?

Why would the the Invoked method stop working? Is it possibly waiting for the lock on methodC to be released before going back to the original lock it was invoked from?

推荐答案

所以,想象一下以下情况:

So, imagine the following situation:


  1. 您后台线程开始运行的代码。它抓住了锁,然后开始运行治法

MethodC 被称作而治法是在其工作的中间。 治法等待锁是免费​​的,阻塞UI线程,直到发生这种情况。

MethodC is called while MethodA is in the middle of its work. MethodA waits for the lock to be free, blocking the UI thread until that happens.

背景线程结束治法,去调用方法b 在UI线程上。 方法b 不能运行,直到消息泵的队列中的所有先前的项目已经完成。

The background thread finishes MethodA and goes to invoke MethodB on the UI thread. MethodB can't run until all previous items in the message pump's queue have finished.

MethodC 是在消息泵的队列的最前面,等到方法b 结束和方法b 是在队列中等待,直到 MethodC 结束。他们彼此都在等待,这是一个僵局。

MethodC is at the top of the message pump's queue, waiting until MethodB finishes, and MethodB is in the queue waiting until MethodC finishes. They are both waiting on each other, which is a deadlock.

那么,你如何解决这个问题?您的真正的需要的是一个锁等待,而无需实际阻塞线程一些方法。幸运的是(在.NET 4.5),这是很容易做到的感谢任务并行库。 (我的报价已经等待,因为我们实际上并不希望等待,我们只是想 MethodC 立即执行的锁被释放的没有的其实等待/阻塞当前线程。)

So, how do you resolve this issue? What you really need is some way of "waiting" on a lock without actually blocking the thread. Fortunately (in .NET 4.5) this is easy to do thanks to the Task Parallel Library. (I have waiting in quotes because we don't actually want to wait, we just want to execute MethodC as soon as the lock is freed without actually waiting/blocking the current thread.)

而不是使用对象 MyLock 是:

private static SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);

现在的 MethodC 你可以这样做:

public async Task MethodC() //you can change the signature to return `void` if this is an event handler
{
    try
    {
        await semaphore.WaitAsync();
        //Do stuff
    }
    finally
    {
        semaphore.Release();
    }
}



这里的关键是,因为我们等待表示,当信号实际上是免费的,我们不会阻止当前线程,这将使其它后台任务编组任务方法b 到UI线程,完成方法,释放信号量,然后让这种方法执行。

The key here is that because we await a task that represents when the semaphore is actually free we aren't blocking the current thread, which will allow the other background task to marshal MethodB to the UI thread, finish the method, release the semaphore, and then let this method execute.

您其他代码并不需要(但还算可以,如果你想)使用异步等待的信号;阻塞后台线程是几乎没有太大的问题,所以唯一关键的变化有正在使用的信号,而不是锁定

Your other code doesn't need to (but still can, if you want) use async waiting on the semaphore; blocking the background thread isn't nearly as much of a problem, so the only key change there is using the semaphore instead of lock:

public void Bar()
{
    try
    {
        semaphore.Wait();
        MethodA(param1, param2);

        MyDelegate del = new MyDelegate(MethodB);
        if (this.IsHandleCreated) this.Invoke(del);
    }
    finally
    {
        semaphore.Release();
    }
}

这篇关于锁内的UI线程调用的方法从()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆