私は「オブジェクトプール」を開発しましたが、「悪い習慣」であるThread.Sleep()を使用せずにそれを行うことはできないようです。
これは、私の他の質問「.netに独自の接続プールを実装する標準的な方法はありますか?」に関連しています。オブジェクトプールの背後にある考え方は、データベース接続に使用される接続プールの背後にある考え方と似ています。ただし、私の場合は、標準のASP.NET Webサービス(IIS6で実行)で限られたリソースを共有するために使用しています。これは、多くのスレッドがこの限られたリソースへのアクセスを要求することを意味します。プールはこれらのオブジェクトをディッシュし(「Get」)、使用可能なすべてのプールオブジェクトが使用されると、次のスレッドは、これらのオブジェクトの1つが再び使用可能になるまで、設定された時間だけ待機します(スレッドはオブジェクトで一度実行された「プット」)。この設定時間内にオブジェクトが使用可能にならない場合、タイムアウトエラーが発生します。
コードは次のとおりです。
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()を取り除くためにこれをどのように書くのですか?
(これを実行したいのは、テストで取得している「false」タイムアウトの原因であると思われるためです。テストアプリケーションには、3つのオブジェクトを含むオブジェクトプールがあります。12スレッドをスピンアップし、各スレッドが取得します。プールからオブジェクトを100回取得します。スレッドがプールからオブジェクトを取得した場合、2,000ミリ秒の間保持し、取得しなかった場合は次の反復に進みます。ロジックは、9つのスレッドが待機することを指示します。 9 x 2,000msは18,000msで、これはスレッドがオブジェクトを待機する必要がある最大時間です。gettimeoutは60,000 msに設定されているため、スレッドはタイムアウトしません。間違っていて、そのThread.Sleepが疑われます)