【问题标题】:Have single-threaded app block till a specific event occurs and then resume让单线程应用程序阻塞,直到发生特定事件然后恢复
【发布时间】:2014-04-04 02:42:49
【问题描述】:

我正在编写一个单线程脚本来对数据库进行大量编程更改。 某些操作会导致数据库执行一些需要一段时间才能完全解决的内部操作。

目前,我的代码包含一个如下所示的方法:

public static void AwaitTemplatePropagation(this Connection conn, DBObject template)
{
    while ((int)template["TransactionCount"] > 0)
    {
        System.Threading.Thread.Sleep(100);
    }
}

基本上,它每 100 毫秒轮询一次,直到未完成的事务计数达到 0。

但是,也可以在 DBObject 类上订阅名为 PropertyUpdated 的事件,该事件将在 TransactionCount 属性更改时引发。我更愿意使用它并让服务器让我知道何时继续,而不是轮询。我想它应该看起来像这样:

public static void AwaitTemplatePropagation(this Connection conn, DBObject template)
{
    template.PropertyUpdated += ???; // Something?

    template.RegisterForPropertyUpdates(new string[] { "TransactionCount" });

    // Magic happens?

    template.UnregisterPropertyUpdates(new string[] { "TransactionCount" });
    template.PropertyUpdated -= ???; // Unsubscribe the event handler
    // Return to the calling function in the main thread
}

我无法弄清楚的是,如何编写一个简单地设置订阅的函数,然后 阻塞 直到触发 PropertyChangedEvent 并显示“TransactionCount 现在为零”?那时我想删除订阅并将执行返回到我在主脚本中间的位置。

我使用的是 .NET 4.0,所以 async/await 关键字不可用。我不确定他们是否会提供帮助。

【问题讨论】:

  • 顺便说一句,如果你安装了Microsoft.Bcl.Async NuGet 包,你可以在 .NET 4.0 上使用async/await

标签: c# multithreading events .net-4.0


【解决方案1】:

您可以使用ManualResetEventSlim

private static ManualResetEventSlim _event = new ManualResetEventSlim (false);

public static void AwaitTemplatePropagation(this Connection conn, DBObject template)
{
    template.PropertyUpdated += OnPropertyUpdated; // Something?

    template.RegisterForPropertyUpdates(new string[] { "TransactionCount" });

    // Magic happens?
    // if you are using this method many times you have to reset the event first
    _event.Reset(); //Sets the state of the event to nonsignaled, which causes threads to block.
    _event.WaitHandle.WaitOne();

    template.UnregisterPropertyUpdates(new string[] { "TransactionCount" });

    // Return to the calling function in the main thread
 }

public void OnPropertyUpdated(...)
{
    _event.Set();
}

ManualResetEventSlim performance

【讨论】:

  • 重复使用一个 ManualResetEventSlim 并重置它,而不是创建一个新的 ManualResetEventSlim 并在我每次调用此函数时进行处理,是否会对性能产生重大影响?
  • 最好重置它,因为它已经是静态的,不需要每次都创建一个新事件。无论如何,如果您创建一个新的或重置它,我认为您不会注意到差异。我添加了一个链接来查看使用 ManualResetEventSlim 与 ManualResetEvent 相比的性能提升。
  • 谢谢米海。你能评论 _event.WaitHandle.WaitOne() 与 _event.Wait() 之间的区别吗?它们对我来说似乎是一样的。
  • @Hydrargyrum 不好意思我有点忙,我认为wait()是基于WaitHandler内部的,我没有深入查看它背后的作用。
  • 是的,如果你从多个线程调用该代码,最好让它像一个实例成员一样,或者使用某种锁来防止并发。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-30
  • 1970-01-01
相关资源
最近更新 更多