C# C中的对象池引发StackoverFlow异常

C# C中的对象池引发StackoverFlow异常,c#,multithreading,locking,stack-overflow,object-pooling,C#,Multithreading,Locking,Stack Overflow,Object Pooling,我试图在C中实现对象池。我的要求是拥有一个可以容纳100个活动SqlConnection对象的池。如果池已经有100个连接,并且如果用户请求新连接,则池必须等待一个现有连接被释放 下面是我使用的代码。在池达到100个正在使用的对象后,我收到StackOverFlow异常 请说明以下代码中StackOverFlow异常的原因 class ObjectPoolingTest { static void Main(string[] args) { int insert

我试图在C中实现对象池。我的要求是拥有一个可以容纳100个活动SqlConnection对象的池。如果池已经有100个连接,并且如果用户请求新连接,则池必须等待一个现有连接被释放

下面是我使用的代码。在池达到100个正在使用的对象后,我收到StackOverFlow异常

请说明以下代码中StackOverFlow异常的原因

class ObjectPoolingTest
{
    static void Main(string[] args)
    {

        int insertedRecords = 1;
        Parallel.For(1, 150000, i =>
        {
            test1(i);
            Console.WriteLine("{0} - Query executed", insertedRecords);
            insertedRecords++;
        }
        );
        Console.ReadKey();

    }

    static void test1(int hitNo)
    {
        var objConnection = Pool.GetConnection();
        SqlCommand cmd = new SqlCommand();
        cmd.Connection = objConnection.ConnectionObject;
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.CommandText = "[dbo].[prSaveRecNumber]";
        cmd.CommandTimeout = 30;
        cmd.Parameters.Add("@recNo", SqlDbType.Int).Value = hitNo;
        int result = cmd.ExecuteNonQuery();
        Pool.ReleaseConnection(objConnection);
        Console.WriteLine(Pool.Message);
    }
}

public class Pool
{
    private static List<Connection> _available = new List<Connection>();
    private static List<Connection> _inUse = new List<Connection>();
    private static int MaxPoolSize = 100;

    private static object lock1 = new Object();
    private static object lock2 = new Object();

    public static string Message
    {
        get
        {
            return string.Format("Available: {0} - InUse: {1}", _available.Count, _inUse.Count);
        }
    }

    public static Connection GetConnection()
    {
        lock (lock1)
        {
            if (_available.Count != 0)
            {
                Connection connection = _available[0];
                _inUse.Add(connection);
                _available.RemoveAt(0);
                return connection;
            }
            else if ((_available.Count + _inUse.Count) != MaxPoolSize)
            {
                Connection connection = new Connection();
                connection.ConnectionObject = new SqlConnection("Server= abcd; Database=sai; User Id=sa; Password=abcd;");

                connection.ConnectionObject.Open();
                _inUse.Add(connection);
                return connection;
            }
            return GetConnection();
        }
    }
    public static void ReleaseConnection(Connection connection)
    {
        lock (lock1)
        {
            _available.Add(connection);
            _inUse.Remove(connection);
        }
    }
}

当达到最大值100时,将递归调用GetConnection。由于您并行执行150000,因此,一旦您在使用中达到100(在本场景中很快发生),您将启动递归调用并最终达到StackOverflowException,因为递归调用的速度比释放的连接快得多,并且发生的调用比可用的连接多得多

如果所需的行为是等待一定时间并重试,则需要重构GetConnection调用,使其处于无限循环中,不断调用相同的代码,直到获得连接为止

您可能还想考虑添加超时值,如果在某一段时间内无法获得连接,则抛出异常。


最后,如果您认为有可能存在可用连接,则可能只希望输入锁定的代码。这会导致对锁进行双重检查,但输入锁定代码的频率会降低。

我建议您学习如何使用调试器。它将快速向您显示代码中发生了什么,您可以快速修复它。另外,既然SqlConnection在内部已经有了池,为什么要自己实现它呢?这与debugger@SamiKuhmonen无关。当使用递归时,无法得到确切的结果。我想实现自己的池只是出于一些明显的原因。谢谢你的回复。问题通过John Koerner解决方案解决,您可以得到准确的结果,因为您捕获了异常并查看其原因。这就是调试器的用途。正如我所说,它会立即显示无限递归问题。谢谢你的解决方案。删除递归方法调用解决了这个问题