gpt4 book ai didi

c# - 从 Lock() 中调用 UI 线程上的方法

转载 作者:太空狗 更新时间:2023-10-30 01:06:39 27 4
gpt4 key购买 nike

我有两个方法,MethodAMethodBMethodB 必须在 UI 线程上运行。我需要它们一个接一个地运行,而不允许 MethodC 在它们之间运行。

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

我为确保这一点所做的是在代码周围放置一个 Lock:

 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.....
}

问题是我卡住了。看起来我的代码陷入了僵局。

当我查看线程时,我发现按钮单击调用的代码卡在 MethodC 中的 lock (MyLock) 处,而我的其他线程似乎卡在 this.Invoke(del).

我读过从 Lock 中调用方法是危险的,但因为我是在那里编写代码的人,而且即使只有 Thread,这似乎也会发生。睡吧 我认为不是代码让我陷入麻烦。

为什么 Invoked 方法会停止工作?在返回调用它的原始锁之前,是否可能等待释放 methodC 上的锁?

最佳答案

那么,想象一下下面的情况:

  1. 您的后台线程开始运行代码。它获取锁,然后开始运行 MethodA

  2. MethodC 被调用,而 MethodA 正在其工作中。 MethodA 等待锁释放,阻塞 UI 线程直到发生这种情况。

  3. 后台线程完成 MethodA 并去调用 UI 线程上的 MethodBMethodB 在消息泵队列中的所有先前项目完成之前无法运行。

  4. MethodC 位于消息泵队列的顶部,等待 MethodB 完成,而 MethodB 在队列中等待直到 MethodC 完成。他们都在等待对方,这是一个僵局。

那么,你是如何解决这个问题的呢?您真正需要的是某种“等待”锁而不实际阻塞线程的方法。幸运的是(在 .NET 4.5 中)由于任务并行库,这很容易做到。 (我在引号中加上了等待,因为我们实际上并不想等待,我们只想在锁定释放后立即执行 MethodC 实际上等待/阻塞当前线程。)

不要为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();
}
}

这里的关键是,因为我们await 一个代表信号量何时真正空闲的任务,所以我们不会阻塞当前线程,这将允许其他后台任务编码MethodB 到UI线程,完成方法,释放信号量,然后让这个方法执行。

您的其他代码不需要(但如果您愿意,仍然可以)在信号量上使用异步等待;阻塞后台线程几乎不是什么大问题,所以唯一的关键变化是使用信号量而不是 lock:

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

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

关于c# - 从 Lock() 中调用 UI 线程上的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14860197/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com