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