- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有两个方法,MethodA
和 MethodB
。 MethodB
必须在 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
上的锁?
最佳答案
那么,想象一下下面的情况:
您的后台线程开始运行代码。它获取锁,然后开始运行 MethodA
。
MethodC
被调用,而 MethodA
正在其工作中。 MethodA
等待锁释放,阻塞 UI 线程直到发生这种情况。
后台线程完成 MethodA
并去调用 UI 线程上的 MethodB
。 MethodB
在消息泵队列中的所有先前项目完成之前无法运行。
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/
我是一名优秀的程序员,十分优秀!