Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 没有线程的共享对象池。睡眠?_C#_.net_Multithreading_Sleep_Pooling - Fatal编程技术网

C# 没有线程的共享对象池。睡眠?

C# 没有线程的共享对象池。睡眠?,c#,.net,multithreading,sleep,pooling,C#,.net,Multithreading,Sleep,Pooling,我已经开发了一个“对象池”,如果不使用Thread.Sleep(),我认为这是一个“糟糕的做法” 这与我的另一个问题有关。对象池背后的思想类似于用于数据库连接的连接池背后的思想。但是,在我的例子中,我使用它来共享标准ASP.NET Web服务(在IIS6中运行)中的有限资源。这意味着许多线程将请求访问这个有限的资源。池将抛出这些对象(一个“Get”),一旦所有可用的池对象都被使用,下一个请求池对象的线程将简单地等待一段时间,以使其中一个对象再次可用(一个线程在处理完对象后将执行一个“Put”)。

我已经开发了一个“对象池”,如果不使用Thread.Sleep(),我认为这是一个“糟糕的做法”

这与我的另一个问题有关。对象池背后的思想类似于用于数据库连接的连接池背后的思想。但是,在我的例子中,我使用它来共享标准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);
        }
    }
}
现在我的问题是:我如何写这个,这样我就摆脱了线程。Sleep()


(我之所以要这样做,是因为我怀疑它要为“虚假”事件负责"测试超时。我的测试应用程序有一个对象池,其中有3个对象。它旋转12个线程,每个线程从池中获取一个对象100次。如果线程从池中获取一个对象,它将保持If 2000毫秒,如果没有,它将进入下一个迭代。现在的逻辑指示9个线程将等待对于任何时间点的对象。9 x 2000 ms是18000 ms,这是任何线程必须等待对象的最长时间。我的get timeout设置为60000 ms,因此任何线程都不应超时。但是,有些线程超时,我怀疑是线程出了问题。Sleep)

因为您已经在使用
lock
,考虑使用<代码>监视器。等待< /COD>和<代码>监视器。 在
Get()
中:


你应该使用信号灯

更新: 信号量是多线程编程的基本结构之一。 信号量可以以不同的方式使用,但基本思想是,当您有一个有限的资源和许多想要使用该资源的客户机时,您可以限制在任何给定时间可以访问该资源的客户机的数量

下面是一个非常粗糙的例子。我没有添加任何错误检查或try/finally块,但您应该这样做

您还可以检查:

假设你有10个水桶和100个想使用这些水桶的人。 我们可以表示队列中的桶

首先,将所有桶添加到队列中

for(int i=0;i<10;i++) 
{
    B.Push(new Bucket());
}
所有客户端在访问队列之前都应该检查信号量。您可能有100个线程运行下面的thread方法。前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();
    }
}

来自单个共享资源的多个读卡器听起来就像一个信号灯。你为什么不使用它?其他人已经回答了你应该做什么。我只想评论一下为什么在这里使用Sleep()是个坏主意——没有任何东西可以保证当线程醒来时池中会有一个对象。因此,如果运气好的话,一个线程可以在其他线程拾取池对象时保持休眠。您需要的是一个等待机制,当对象可用时,它将唤醒线程。这是一个优秀、简单的解决方案,不会对我现有的代码进行太多更改。正如其他人所解释的,我应该使用信号量,但正如我的测试所示,这将很好地完成。谢谢你,亨克。这是一种信号灯。Monitor是完全受管理的代码,应该是首选,只在需要时使用“更重”的代码。是的,我从文档中看到您是对的,但是我似乎无法让我的大脑绕过它。
lock (fSyncRoot)
{
   fQueue.Enqueue(aObject);
   if (fQueue.Count == 1)
         Monitor.Pulse(fSyncRoot);
}
for(int i=0;i<10;i++) 
{
    B.Push(new Bucket());
}
Semaphore s = new Semaphore(0, 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();
    }
}