我有两种方法,MethodA
& MethodB
. MethodB
必须在 UI 线程上运行。我需要他们在不允许的情况下一个接一个地运行MethodC
在他们之间奔跑。
MethodC
当用户单击一个可爱的小按钮时调用。
我做了什么来确保这是一个Lock
围绕代码:
lock (MyLock)
{
MethodA(param1, param2);
MyDelegate del = new MyDelegate(MethodB);
if (this.IsHandleCreated) this.Invoke(del);
}
And for MethodC
:
public void MethodC()
lock (MyLock)
{
Do bewildering stuff.....
}
问题是我被卡住了。看起来我的代码陷入了僵局。
当我查看线程时,我发现按钮单击调用的代码被卡在lock (MyLock)
in MethodC
我的另一个线程似乎卡在this.Invoke(del)
.
我读过从内部调用方法是危险的Lock
但因为我是在那里编写代码的人,即使只用一个,这似乎也会发生Thread.Sleep
我认为这不是给我带来麻烦的代码。
为什么 Invoked 方法会停止工作?
是否有可能等待锁定methodC
在返回到调用它的原始锁之前要释放它吗?
那么,想象一下以下情况:
您的后台线程开始运行代码。它抓住锁然后开始运行MethodA
.
MethodC
被调用时MethodA
正在工作中。MethodA
等待锁释放,并阻塞 UI 线程,直到释放为止。
后台线程结束MethodA
并去调用MethodB
在 UI 线程上。MethodB
在消息泵队列中的所有先前项目完成之前无法运行。
MethodC
位于消息泵队列的顶部,等待直到MethodB
完成,并且MethodB
在队列中等待直到MethodC
完成。两人都在等待对方,陷入了僵局。
那么,你如何解决这个问题呢?你什么reallyneed 是某种“等待”锁而不实际阻塞线程的方式。幸运的是(在 .NET 4.5 中)借助任务并行库,这很容易做到。 (我在引号中等待,因为我们实际上不想等待,我们只想执行MethodC
一旦锁被释放without实际上正在等待/阻塞当前线程。)
而不是使用object
for MyLock
use:
private static SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
Now for 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();
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)