Monitor.TryEnter不起作用

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)

  • 使用`SemaphoreSlim`的代码将一个接一个地等待并执行.如果另一个代码已经在执行,则使用`Interlocked`的代码将不会执行. (3认同)

poy*_*poy 6

您不能await在Monitor.TryEnter()和Monitor.Exit()方法调用之间使用.之后await,线程上下文可能会有所不同,这意味着线程没有entered锁定,因此它无法实现exit.

事实上,如果您使用lock关键字,编译器将保护您:

lock(_sync)
{
  await Task.Delay(...); // <- Compiler error...
}
Run Code Online (Sandbox Code Playgroud)