我已经开发了一个“对象池”,如果不使用Thread.Sleep(),似乎无法做到这一点,我认为这是“糟糕的做法”。
这与我的另一个问题"Is there a standard way of implementing a proprietary connection pool in .net?“有关。对象池背后的思想类似于用于数据库连接的连接池背后的思想。然而,在我的例子中,我使用它来共享标准ASP.NET Web服务(在IIS6中运行)中的有限资源。这意味着许多线程将请求访问这个有限的资源。池将分配这些对象(“Get”),一旦所有可用的池对象都被使用,下一个请求池对象的线程将简单地等待一段时间,等待这些对象中的一个对象再次可用(一旦对象完成,线程将执行"Put“操作)。如果一个对象在此设置时间内不可用,则将发生超时错误。
代码如下:
public class SimpleObjectPool
{
private const int cMaxGetTimeToWaitInMs = 60000;
private const int cMaxGetSleepWaitInMs = 10;
private object fSyncRoot = new object();
private Queue<object> fQueue = new Queue<object>();
private SimpleObjectPool()
{
}
private static readonly SimpleObjectPool instance = new SimpleObjectPool();
public static SimpleObjectPool Instance
{
get
{
return instance;
}
}
public object Get()
{
object aObject = null;
for (int i = 0; i < (cMaxGetTimeToWaitInMs / cMaxGetSleepWaitInMs); i++)
{
lock (fSyncRoot)
{
if (fQueue.Count > 0)
{
aObject = fQueue.Dequeue();
break;
}
}
System.Threading.Thread.Sleep(cMaxGetSleepWaitInMs);
}
if (aObject == null)
throw new Exception("Timout on waiting for object from pool");
return aObject;
}
public void Put(object aObject)
{
lock (fSyncRoot)
{
fQueue.Enqueue(aObject);
}
}
}要使用它,需要执行以下操作:
public void ExampleUse()
{
PoolObject lTestObject = (PoolObject)SimpleObjectPool.Instance.Get();
try
{
// Do something...
}
finally
{
SimpleObjectPool.Instance.Put(lTestObject);
}
}现在我的问题是:我该如何编写它,这样才能摆脱Thread.Sleep()?
(我之所以要这样做,是因为我怀疑它是我在测试中得到的“假”超时的原因。我的测试应用程序有一个包含3个对象的对象池。它向上旋转12个线程,每个线程从池中获取一个对象100次。如果线程从池中获得一个对象,它会在2,000ms内保持If,如果没有,它将进入下一次迭代。现在,逻辑规定9个线程将在任何时间点等待对象。9 x 2,000毫秒等于18,000毫秒,这是任何线程等待对象的最大时间。我的get超时设置为60,000毫秒,因此任何线程都不会超时。然而,有些人这样做是有问题的,我怀疑是Thread.Sleep)
发布于 2009-10-11 00:08:25
由于您已经在使用lock,因此请考虑使用Monitor.Wait和Monitor.Pulse
在Get()中
lock (fSyncRoot)
{
while (fQueue.Count < 1)
Monitor.Wait(fSyncRoot);
aObject = fQueue.Dequeue();
}在Put()中
lock (fSyncRoot)
{
fQueue.Enqueue(aObject);
if (fQueue.Count == 1)
Monitor.Pulse(fSyncRoot);
}发布于 2009-10-11 00:23:37
您应该使用信号量。
http://msdn.microsoft.com/en-us/library/system.threading.semaphore.aspx
更新:信号量是多线程编程的基本结构之一。信号量可以以不同的方式使用,但基本思想是,当您有一个有限的资源,并且有许多客户端希望使用该资源时,您可以限制在任何给定时间可以访问该资源的客户端的数量。
下面是一个非常粗糙的例子。我没有添加任何错误检查或try/finally块,但您应该添加。
您还可以查看:http://en.wikipedia.org/wiki/Semaphore_(programming)
假设你有10个水桶,100个人想要使用这些水桶。我们可以表示队列中的存储桶。
开始时,将所有存储桶添加到队列中
for(int i=0;i<10;i++)
{
B.Push(new Bucket());
}现在创建一个信号量来保护您的存储桶队列。这个信号量是在不触发任何项的情况下创建的,容量为10。
Semaphore s = new Semaphore(0, 10);所有客户端在访问队列之前都应该检查信号量。你可能有100个线程在运行下面的线程方法。前10个将传递信号量。其他人都会等着。
void MyThread()
{
while(true)
{
// thread will wait until the semaphore is triggered once
// there are other ways to call this which allow you to pass a timeout
s.WaitOne();
// after being triggered once, thread is clear to get an item from the queue
Bucket b = null;
// you still need to lock because more than one thread can pass the semaphore at the sam time.
lock(B_Lock)
{
b = B.Pop();
}
b.UseBucket();
// after you finish using the item, add it back to the queue
// DO NOT keep the queue locked while you are using the item or no other thread will be able to get anything out of it
lock(B_Lock)
{
B.Push(b);
}
// after adding the item back to the queue, trigger the semaphore and allow
// another thread to enter
s.Release();
}
}https://stackoverflow.com/questions/1549409
复制相似问题