Tar*_*Tar 14 c# wpf multithreading
我的代码隐藏的一部分:
object _sync = new object();
private async void OnKeyDown(object sender, KeyEventArgs e) {
if (!Monitor.TryEnter(_sync)) return;
Trace.Write("taken...");
await Task.Delay(TimeSpan.FromSeconds(5));
Trace.WriteLine(" done");
Monitor.Exit(_sync);
}
Run Code Online (Sandbox Code Playgroud)
输出(在不到5秒的时间内按下几次):
taken...taken...taken... done
done
done
Run Code Online (Sandbox Code Playgroud)
怎么会??该_sync锁是永远不会上当受骗,为什么呢?
Mar*_*ell 16
混合Monitor并且await......有点风险.看起来你要做的就是确保它一次只运行一次.我怀疑Interlocked可能更简单:
object _sync = new object();
int running = 0;
private async void OnKeyDown(object sender, KeyEventArgs e) {
if(Interlocked.CompareExchange(ref running, 1, 0) != 0) return;
Trace.Write("taken...");
await Task.Delay(TimeSpan.FromSeconds(5));
Trace.WriteLine(" done");
Interlocked.Exchange(ref running, 0);
}
Run Code Online (Sandbox Code Playgroud)
请注意,您可能还想想如果发生错误等会发生什么; 该值如何重置?您可以使用try/ finally:
if(Interlocked.CompareExchange(ref running, 1, 0) != 0) return;
try {
Trace.Write("taken...");
await Task.Delay(TimeSpan.FromSeconds(5));
Trace.WriteLine(" done");
} finally {
Interlocked.Exchange(ref running, 0);
}
Run Code Online (Sandbox Code Playgroud)
Ste*_*ary 12
你不能使用线程仿射型样Monitor带await.在这种特殊情况下,您总是在同一个线程(UI线程)上获取锁,并且这种类型的锁允许递归锁定.
尝试SemaphoreSlim改为(WaitAsync而Release不是Enter和Exit):
SemaphoreSlim _sync = new SemaphoreSlim(1);
private async void OnKeyDown(object sender, KeyEventArgs e) {
await _sync.WaitAsync();
Trace.Write("taken...");
await Task.Delay(TimeSpan.FromSeconds(5));
Trace.WriteLine(" done");
_sync.Release();
}
Run Code Online (Sandbox Code Playgroud)
您不能await在Monitor.TryEnter()和Monitor.Exit()方法调用之间使用.之后await,线程上下文可能会有所不同,这意味着线程没有entered锁定,因此它无法实现exit.
事实上,如果您使用lock关键字,编译器将保护您:
lock(_sync)
{
await Task.Delay(...); // <- Compiler error...
}
Run Code Online (Sandbox Code Playgroud)