螺纹安全静电

时间:2012-08-14 13:52:20

标签: c# static race-condition

我遇到了一些像这样的代码。

public class ConnectionUtility
{
    private static SqlConnection con;

    public static SqlConnection GimmeConnection()
    {
        if(con==null)
            con = new SqlConnection();
        return con;
    }
}

这是在ASP.NET Web应用程序中。可以预期会有竞争条件,其中一个请求/页面尝试打开/关闭连接上的执行事物,而其他请求也尝试执行这些操作吗?

5 个答案:

答案 0 :(得分:4)

是的,那里肯定有竞争条件。多个线程可能同时调用GimmeConnection()并且都创建一个新连接,因此con的初始化存在竞争条件。

在.NET中执行此操作的正确方法实际上非常简单:

public class ConnectionUtility
{
    private static SqlConnection con = new SqlConnection();

    public static SqlConnection GimmeConnection()
    {
        return con;
    }
}

这保证可以正常工作,没有任何竞争条件。

当然,还有另一种可能的竞争条件,这不是由此确定的:

由于您创建了一个可全局访问的连接,因此多个线程可以轻松地同时使用它,这是不安全的。

如果连接由多个线程使用,则必须显式序列化这些访问,例如通过锁定。

当然,最佳行动方案仍然只是avoid singletons ......

答案 1 :(得分:1)

是的...您不应该在多个线程之间共享一个静态连接。这不仅仅是竞争条件问题 - 您将有许多网页试图同时使用相同的连接,这将无法正常工作。

您可以在“con”上使用[ThreadStatic]属性,这将使其在线程范围内为全局。

答案 2 :(得分:1)

是的,你可以期待这样的竞争条件。很好的发现!

答案 3 :(得分:1)

两种竞争条件,一种可能是无害的,一种是可怕的。还有一个逻辑错误。

潜在无害的一个是构造函数逻辑:

if(con==null)
  con = new Thing();

如果你想使用单个对象作为优化,这可能是无害的,但是使用一个多于一个的句点仅仅是次优的而不是错误的(不是每个种族都是世界末日)。这取决于Thing是什么以及它是如何使用的。

灾难性的种族是:

return con;

因为在这种情况下,类型是SqlConnection,这不是线程安全的,所以每次使用该属性都是一场惹恼灾难的种族。

逻辑错误在于让单例缓存成为一个很轻的对象,它可以处理它自己的重要部分的线程安全池。由于这种合并,你不应该坚持SqlConnection超过绝对必要的时间。实际上,如果你在一次使用和另一次使用之间存在差距(虽然本身就是一种难闻的气味),你应该关闭它并再次重新打开它。这使得SqlConnection为您提供的线程安全池,在使用之间以最佳方式工作。

答案 4 :(得分:0)

每当写单身时,你应该让它们成为线程安全的:

  class Singleton 
  {
    private Singleton() { }
    private static volatile Singleton instance;

    public static Singleton GetInstance() 
    {
       // DoubleLock
       if (instance == null) 
       {
          lock(m_lock) {  
             if (instance == null) 
             { 
                instance = new Singleton();
             }   
          }
       }
       return instance;
    }

    // helper
    private static object m_lock = new object();
  }