【问题标题】:Can I use a C# SemaphoreSlim to trigger something我可以使用 C# SemaphoreSlim 来触发某些东西吗
【发布时间】:2020-07-03 00:36:28
【问题描述】:

是否可以使用 SemaphoreSlim(或者应该使用其他什么东西?)一个线程来触发另一个线程,有没有办法清除过早的触发器? 这是异步代码,所以我松散地使用“线程”。

SemaphoreSlim ready = new SemaphoreSlim(0, 1);

// Thread 1
...
ready.CurrentCount = 0;  // Can't do this, but somehow clear any premature triggers
DoSomething();           // this will eventually cause other thread to release
await ready.WaitAsync(); // wait for trigger
DoNextThing();
...

// Thread 2
...
ready.Release(); // trigger waiting thread to proceed
...

【问题讨论】:

  • 这感觉像是 XY 问题 - meta.stackexchange.com/questions/66377/what-is-the-xy-problem。请详细说明根本问题。
  • 解释你想要实现的目标。例如:你的用例是什么。这将有助于回答您的问题。
  • 投票结束...这个问题需要更清楚,已经有一个很好的答案,但我担心除了猜测你想要完成的事情之外,没有足够的信息来做任何事情实际问题是什么。您还应该阅读How to Ask
  • 事件对象可用于释放其他等待线程。如果没有其他线程在等待该对象,则不会发生任何事情。

标签: c# asynchronous synchronization semaphore


【解决方案1】:

是的,您可以使用SemaphoreSlim 作为异步工作流的协调原语。它非常适合这项工作。另一种方法是使用TaskCompletionSource。每个选项各有利弊。

SemaphoreSlim的优势:

  1. 内置支持可选取消,重载WaitAsync(CancellationToken cancellationToken)
  2. 内置支持可选超时,过载WaitAsync(TimeSpan timeout)
  3. 它是可重复使用的。

TaskCompletionSource的优势:

  1. 内置支持异步延续(选项RunContinuationsAsynchronously)。
  2. 可以传播超出完成信号的额外状态。
  3. 可以传播取消和失败。
  4. SemaphoreSlim更轻量级。
  5. 更能表达其意图。

用于TaskCompletionSource 的泛型类型TResult 的类型通常是完成值为truebool,或完成值为nullobject。在大多数情况下,结果是无关紧要的,因此您可以选择您喜欢的任何类型和值。


更新:以下是在工作流 2 准备好接受信号之前阻止工作流 2 向工作流 1 发送信号的方法:

private volatile TaskCompletionSource<object> _ready;

// Workflow 1
//...
_ready = new TaskCompletionSource<object>(); // Start accepting signals
DoSomething(); // This will eventually cause other workflow to send a signal
await ready.Task; // Wait for a signal
_ready = null; // Stop accepting signals
DoNextThing();
//...

// Workflow 2
//...
_ready?.TrySetResult(null); // Send signal to waiting workflow, if it accepts signals

添加了volatile 以确保可见性(所有工作流都可以“看到”_ready 字段的最新值)。但它不强制执行任何类型的同步。如果您希望保证_ready 字段将按特定顺序访问,则需要添加适当的同步(lockInterlocked 等)。在这种情况下,volatile 是多余的,应该删除。

【讨论】:

  • 谢谢。我不知道TaskCompletionSource。似乎它也可以传递对我有用的数据。我想不出比 while (ready.CurrentCount > 0) await ready.WaitAsync();; 更好的方法了丢弃虚假触发器,因为第二个线程正在从其他地方接收数据,我只想要第一个线程操作后的实例。
  • @Codemeister 我用一个可能解决这个问题的例子更新了我的答案。
  • 非常好。谢谢。
猜你喜欢
  • 2014-12-17
  • 2020-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多