靜態線程安全 (Thread safety of static)


問題描述

靜態線程安全 (Thread safety of static)

I came across some code like this.

public class ConnectionUtility
{
    private static SqlConnection con;

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

This is in an ASP.NET web application. Can one expect there to be race conditions where one request/page tries to open/close execute things on the connection and other request tries to do those things as well?

‑‑‑‑‑

參考解法

方法 1:

Yes, a race condition is definitely possible there. Multiple threads might concurrently call GimmeConnection() and all create a new connection, so there is a race condition on the initialization of con.

The correct way to do this in .NET is actually fairly simple:

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

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

This is guaranteed to work, without any race conditions.

Of course, there is also another possible race condition, which is not fixed by this:

Because you create one single globally accessible connection, it is easy for multiple threads to use it concurrently, which is not safe.

If the connection is used by multiple threads, these accesses must be explicitly serialized, for example through locking.

Of course, the best course of action is still to just avoid singletons in the first place...

方法 2:

Yes... You shouldn't share a single static connection along multiple threads. This is not only a race condition issue ‑ you will have many web pages trying to use the same connection at the same time which won't work.

You can use the [ThreadStatic] attribute on your "con" which will make it global on thread scope.

方法 3:

Yes, you can expect such race conditions. Good spotting!

方法 4:

Two race conditions, one potentially harmless, one dreadful. There's also a logical error.

The potentially harmless one is in the constructor logic of:

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

This can be harmless if you want to use a single object as an optimisation, but having a period where more than one is used is merely sub‑optimal rather than wrong (not every race is the end of the world). It depends on just what Thing is and how it's used.

The disastrous race is:

return con;

Because in this case the type is SqlConnection, which is not thread‑safe, so every single use of the property is a race that is courting disaster.

The logical error is in having a singleton cache an object which is light to produce and which handles its own thread‑safe pooling of the heavy part. Because of this pooling, you shouldn't hold on to an SqlConnection any longer than absolutely necessary. Indeed, if you've a gap between one use and another (a bad smell in itself though), you should close it and re‑open it again. This makes the thread‑safe pooling that SqlConnection provides for you, work at it most optimal between uses.

方法 5:

Whenever writing singletons, you should make make them threadsafe:

  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();
  }

(by MatthewMartinjalfAlvaro RodriguezDaren ThomasJon Hannaoopbase)

參考文件

  1. Thread safety of static (CC BY‑SA 3.0/4.0)

#race-condition #static #C#






相關問題

Javascript 和 DOM 事件交互和可能的競爭條件 (Javascript and DOM event interaction and possible race conditions)

防禦 System.Collections.Concurrent.ConcurrentDictionary 中的競爭條件 (Defending against race conditions in System.Collections.Concurrent.ConcurrentDictionary)

可能一次在 PHP 中多次寫入同一個文件? (Potentially write to same file in PHP multiple times at once?)

靜態線程安全 (Thread safety of static)

CancellationTokenSource.Cancel 引發 ObjectDisposedException (CancellationTokenSource.Cancel throws an ObjectDisposedException)

如何處理 Web 應用邏輯和數據庫並發? (How to handle Web application logic and database concurrency?)

Linux IRQ 處理程序中的固有競爭條件 (Inherent race condition in Linux IRQ handlers)

SQL Server 進程隊列競爭條件 (SQL Server Process Queue Race Condition)

WCF 服務僅在客戶端收到結果時才寫入日誌 (WCF service writes log only if client receives results)

將 SWT 與 JOGL 一起使用時發生隨機崩潰(競爭條件?) (Random crashes when using SWT with JOGL (race condition?))

std::shared_ptr 的線程安全 (Thread safety with std::shared_ptr)

如何更新 JSON 類型列中的特定值 (How can I update specific value from my JSON type column)







留言討論