【问题标题】:Async Method calls calling Sync method call异步方法调用调用同步方法调用
【发布时间】:2009-09-23 16:44:46
【问题描述】:

我正在开发一个线程安全类,我想将异步方法调用包装在同步方法调用周围。也许我不是在寻找“asynccall”方法的定义,而是在寻找接近它的东西。在实例上调用 AsyncToStartSearchPage() 时,我希望调用线程阻塞,直到新线程获得对象上的锁。这就是信号量的用武之地。 asyncCalls 锁是为了限制使用。也许这不是最好的实现,但我觉得它需要某种方式来限制一次异步请求的数量。任何反馈都会很棒。 应用程序的用途是我有一个消费者/生产者模型,其中调用此方法的线程将开始 ToStartPage() 方法调用并将其放入缓冲区中。另一方面,我希望线程在 ToStartPage() 完成之前无法更改对象的状态来获取对象。在此之前,我遇到过消费者在线程旋转能够获得锁定并执行 ToStartPage() 之前获得对象锁定的问题。

    private readonly Object obj_Lock = new Object();
    private readonly Object asyncCalls = new Object();
    private Semaphore asyncSema = new Semaphore(0, 1);

    //sync method call which has a async calling wrapper
    public void ToSearchPage()
    {
        lock (obj_Lock)
        {

             //do something
        }
    }

    //public async method wrapper
    public bool AsyncToStartSearchPage()
    {
        //used to limit one async call.
        //not crazy about this part, but I feel it needs something like this
        if (Monitor.TryEnter(asyncCalls, 1))
        {
            try
            {
                Thread t = new Thread(asyncToStartPage);
                t.Start();

                //  blocks until the new thread obtains lock on object
                asyncSema.WaitOne();
            }
            finally
            {
                Monitor.Exit(asyncCalls);

            }
                return true;
        }
        else
        {
            return false;
        }

    }



    private void asyncToStartPage()
    {
        lock (obj_Lock)
        {
            //  now that I have aquired lock, release calling thread
            asyncSema.Release();
            ToSearchPage();
        }
    }

【问题讨论】:

  • 答:这个模型能用吗? B:任何关于更好实施的建议。
  • 您想限制异步调用,但您想在此限制过程中阻塞调用线程?您可能想问一个不同的问题,详细说明您的要求并寻求建议。
  • 这行得通吗?也许。我不想在没有彻底测试的情况下猜测某些多线程代码是否可以工作。
  • 线程 A 将在 obj 放入阻塞缓冲区之前调用 AsyncToStartSearchPage(),其中线程 B 将等待将 obj 从缓冲区中取出,假设 obj 处于由操作 ToSearchPage()。我不希望 A 或 B 等待 ToSearchPage() 调用,所以我希望它是异步的以减少这种机会。通话可能需要几秒钟。需要更多细节?
  • 所以如果线程 A 创建线程 C 来处理 ToSearchPage() 方法,那么线程 A 会将 obj 放入缓冲区。如果 A 将 obj 放入缓冲区,B 检索 obj 并在 C 获得锁之前获得锁,那我就痛苦了。

标签: c# .net multithreading asynchronous


【解决方案1】:

更简洁的替代方案可能如下所示。您不需要信号量来让调用线程等待直到获得锁。请注意我是如何使用 ManualResetEvent 并为此目的制作冗余锁结构的。一旦获得外锁,就会发出事件信号,并且由于锁是可重入的,因此将立即获得内锁。现在,我使用信号量来限制 AsyncToSearchPage 的执行。

public class YourThreadSafeClass
{
  private Object m_Lock = new Object();
  private Semaphore m_Semaphore = new Semaphore(1, 1);

  public void ToSearchPage()
  {
    lock (m_Lock)
    {
       // Actual work goes here.
    }
  }

  public bool AsyncToSearchPage()
  {
    // Throttle access using a semaphore
    if (m_Semaphore.WaitOne(0)) 
    {
      try 
      { 
        ManualResetEvent e = new ManualResetEvent(false);
        Thread t = new Thread(
            () =>
            {
              // Acquire the lock here for the purpose of signalling the event
              lock (m_Lock)
              {
                e.Set();
                ToSearchPage(); // The lock will be acquired again here...thats ok
              }
            }
          );
        t.Start();
        e.WaitOne(); // Wait for the lock to be acquired
        return true;
      }
      finally 
      {
        // Allow another thread to execute this method
        m_semaphore.Release();
      } 
    }
    return false;
  }
}

请记住,这是一种更简洁的方式来做同样的事情。但是,我建议完全避免这种方法,因为它仍然很难看。我并不真正理解需要限制对异步方法的访问,也不是让它阻塞,直到包装的同步方法无论如何都获得它的锁。相反,请考虑在整个 .NET Framework 中使用的 BeginXXX/EndXXX 异步模式。

【讨论】:

    【解决方案2】:

    Spring 的 @Scheduled 和 @Async 支持将是最好的解决方案

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-09-23
      • 2015-11-09
      • 1970-01-01
      • 2020-12-19
      • 1970-01-01
      • 2015-11-28
      相关资源
      最近更新 更多