如何永远等待直到引发事件? [复制]
Posted
技术标签:
【中文标题】如何永远等待直到引发事件? [复制]【英文标题】:How to wait forever until an event is raised? [duplicate] 【发布时间】:2021-06-27 13:00:33 【问题描述】:我很确定这有一个相对简单的答案,但不知何故我找不到它。
在处理事件的控制台应用程序示例中(例如https://www.rabbitmq.com/tutorials/tutorial-six-dotnet.html,但我也见过很多其他的)我看到这样的代码:
public static void Main()
var someObject = new MyClassWithEvents();
someObject.SomeEventFired += () =>
// do whatever
;
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
现在明显的问题是,如果您超出示例代码(您可以在其中等待按键被按下)并删除 Console.ReadLine()
线程退出(或者如果您不在 Main()
中,您脱离上下文)并且不再处理事件。
我想我可以使用一个永恒的while(true) Sleep()
,但这不会也阻止线程接收事件吗?
编写这种程序的正确方法是什么?这个想法是它看起来很像一个服务,等待在那里什么都不做,直到一个事件被触发。
要了解我的意思,请尝试以下代码:
public static void Main()
var someObject = new MyClassWithEvents();
someObject.SomeEventFired += () =>
// do whatever
;
这立即存在!
TIA,
吉姆
【问题讨论】:
旋转等待是您最不想要的。但是让我们假设您找到了一种在没有Console.ReadLine()
的情况下“永远等待”的方法。你的程序应该如何终止?绝不?那么服务可能正是您真正想要的?
那么这可能是你感兴趣的:ManualResetEventSlim
对@RandRandom,谢谢,就是这个意思,这不会立即退出吗?如果第一个事件在几分钟后发生怎么办?
正确的家伙,确切地说,我这些天的具体例子是 rabbitmq 队列,但 FileSystemWatcher 也是一个很好的例子。
是的,那当然是另一回事了。 @Fildor 的水晶球比我的更准确。 :)
【参考方案1】:
尚未对此进行测试,但我会尝试这是最简单的方法:
public static ManualResetEventSlim waiter = new ManualResetEventSlim(false);
public static void Main()
var someObject = new MyClassWithEvents();
someObject.SomeEventFired += () =>
// do whatever
;
// Just an example for an "Exit-Trigger"
someObject.ExitProgramEventFired += () =>
waiter.Set(); // Signal the MRE to stop blocking.
;
waiter.Wait(); // Blocks until signalled.
Console.WriteLine("Exit Program has been triggered.");
// Cleanup resources ...
注意:Wait
方法还带有支持取消和超时的重载,因此您可以真正强化您的设计。
供参考:ManualResetEventSlim
【讨论】:
【参考方案2】:如果您使用的是较新版本的 .Net,您可以将入口点设为 Task Main
而不是 void Main
。然后您可以使用TaskCompletionSource
返回一个任务,该任务将在按下取消键时完成。
这样做应该将主线程释放回线程池,这意味着它应该使用更少的资源。
public static Task Main(string[] args)
// Set up TaskCompletionSource that completes when the CancelKey is Pressed
var taskCompletionSource = new TaskCompletionSource<bool>();
Console.CancelKeyPress += (_, args) =>
args.Cancel = true;
taskCompletionSource.TrySetResult(true);
;
var someObject = new MyClassWithEvents();
someObject.SomeEventFired += () =>
// do whatever
;
return taskCompletionSource.Task;
应该提一下,你问'那会不会也阻止线程接收事件',但这不应该是一个问题。回调通常不会在主线程上返回,它们通常由线程池中的随机空闲线程处理。所以即使主线程被什么东西阻塞了,这样的回调通常仍然会运行。
【讨论】:
这只是将事件处理程序包装到任务中还是目的是什么? @user3625699 是的,这只是向 Main() 返回一个任务,除非要求关闭应用程序,否则该任务永远不会完成。主要是返回到 Main 的任务没有完成并且没有使用什么都不做的线程。以上是关于如何永远等待直到引发事件? [复制]的主要内容,如果未能解决你的问题,请参考以下文章