异步方法调用调用Sync方法调用

时间:2009-09-23 16:44:46

标签: c# .net multithreading asynchronous

我正在开发一个线程安全类,我想围绕同步方法调用包装异步方法调用。也许我不是在寻找“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();
        }
    }

2 个答案:

答案 0 :(得分:2)

更清洁的替代方案可能如下所示。您不需要信号量来让调用线程等到获取锁定。请注意我是如何使用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异步模式。

答案 1 :(得分:0)

Spring的@Scheduled和@Async支持

是最好的解决方案