programing

정적 변수는 스레드 안전합니까? C#

randomtip 2023. 8. 9. 23:02
반응형

정적 변수는 스레드 안전합니까? C#

DataTables를 저장하는 클래스를 만들고 싶습니다. 이렇게 하면 응용 프로그램에서 검색할 때마다 세부 정보 목록을 가져올 수 없습니다.따라서 이 작업은 한 번 수행해야 합니다. 아래 코드가 수행하는 것으로 알고 있습니다. 하지만 스레드 세이프인지는 잘 모르겠습니다.

아래 코드는 3계층 애플리케이션의 비즈니스 계층 섹션에 있으며 데이터 테이블을 프레젠테이션 계층으로 반환합니다.

public class BusinessLayerHandler
{
    public static DataTable unitTable;
    public static DataTable currencyTable;

    public static DataTable GetUnitList()
    {
        //import lists each time the application is run
        unitTable = null;
        if (unitTable == null)
        {
            return unitTable = DatabaseHandler.GetUnitList();
        }
        else
        {
            return unitTable;
        }
    }

    public static DataTable GetCurrencyList()
    {
        //import lists each time the application is run
        currencyTable = null;
        if (currencyTable == null)
        {
            return currencyTable = DatabaseHandler.GetCurrencyList();
        }
        else
        {
            return currencyTable;
        }
    }

도움을 주시면 감사하겠습니다. 데이터 테이블을 캐시하는 더 좋은 방법이 있다면 알려주시기 바랍니다.

업데이트:

당신의 의견 덕분에, 제가 올바르게 이해했다면, 이것이 제안된 방법입니다.

public class BusinessLayerHandler
{
    private static DataTable unitTable;
    private static DataTable currencyTable;

    private static readonly object unitTableLock = new object();
    private static readonly object currencyTableLock = new object();

    public static DataTable GetUnitList()
    {
        //import lists each time the application is run
        //unitTable = null;

        lock (unitTableLock)
        {
            if (unitTable == null)   
            {
                return unitTable = DatabaseHandler.GetUnitList();
            }
        }
        return unitTable;
    }

    public static DataTable GetCurrencyList()
    {
        //import lists each time the application is run
        lock (currencyTableLock)
        {
            if (currencyTable == null)
            {
                return currencyTable = DatabaseHandler.GetCurrencyList();
            }
        }
        return currencyTable;
    }
}

한 번 로드하고 참조를 유지하기만 하면 됩니다.변수가 null이면 변수를 초기화하기만 하면 됩니다.Null 확인, 잠금 및 다시 Null 확인을 Double Check Locking이라고 하며 사용자에게 적합합니다.별도의 잠금 개체를 제공하는 것이 가장 좋습니다. 따라서 잠금의 세부적인 부분을 효과적으로 제어할 수 있습니다.

이것이 사람들이 내부의 가치를 변형시키는 것을 막지는 않습니다.DataTable동시에 정적 멤버를 초기화하려는 사람들을 막을 뿐입니다.

private static readonly object UnitTableLock = new object();
private static DataTable unitTable;
private static bool _ready = false;

public static DataTable GetUnitList()
{
    if (!_ready)
    {
        lock (UnitTableLock)
        {
            if (!_ready)
            {
                unitTable = new DataTable; //... etc
                System.Threading.Thread.MemoryBarrier();
                _ready = true;
            }
        }
    }

    return unitTable;
}

의 결과에서만 읽힙니다.GetUnitList절대 편지를 쓰지 않습니다.

http://en.wikipedia.org/wiki/Double-checked_locking 참조하여 수정됨

Double Check Locking은 그 이후로 .net 프레임워크 4.0에서 구현된 클래스로 추가할 가치가 있다고 생각했습니다. 따라서 클래스에 잠금을 기본적으로 포함시키려면 다음과 같이 사용할 수 있습니다.

public class MySingleton
{
    private static readonly Lazy<MySingleton> _mySingleton = new Lazy<MySingleton>(() => new MySingleton());

    private MySingleton() { }

    public static MySingleton Instance
    {
        get
        {
            return _mySingleton.Value;
        }
    }
}

그것들은 스레드 세이프가 아닙니다.예를 들어, 잠금 연산자를 사용하여 논리 스레드를 안전하게 만드는 것을 고려해야 합니다.

.net 4에 있는 경우 데이터 테이블에서 ThreadLocal 래퍼를 사용할 수 있습니다.

정적 변수는 스레드 자체로 안전하지 않습니다.나사산 안전을 염두에 두고 설계해야 합니다.

시작할 수 있는 좋은 링크가 있습니다. http://en.csharp-online.net/Singleton_design_pattern%3A_Thread-safe_Singleton

이와 별도로 기존 DataTable보다 더 현대적인 접근 방식을 사용할 것을 강력히 권장합니다.엔티티 프레임워크 또는 NHibernate를 확인하십시오.이를 데이터 계층에 구현하면 나머지 소프트웨어에서 데이터베이스 세부 정보를 숨기고 상위 수준의 추상화(POCO 개체)에서 작동할 수 있습니다.

당신은 괜찮아야 할 것 같아요.2개의 스레드가 데이터 테이블이 null임을 결정하고 둘 다 테이블을 읽지만 하나만 할당할 수 있습니다.unitTable/currencyTable마지막으로 참조하십시오. 따라서 최악의 경우 두 번 이상 초기화합니다.하지만 일단 준비가 되면 당신이 좋을 것 같아요.당신이 그들에게 편지를 쓰지 않는 한.극장은 일관성 없는 상태로 남을 수 있습니다.

만약 당신이 더블을 피하고 싶다면 당신은 전체 게터 코드를 포장할 수 있습니다.lock진술.이것은 싱글톤을 초기화하는 것과 비슷합니다.

또한 참조를 다시 null로 설정하여 강제로 새로 고칠 수 있는 방법을 추가합니다.

GJ

데이터 테이블이 읽기 전용인 경우 데이터 테이블을 채울 때 잠가야 하며 변경되지 않으면 스레드 안전합니다.

public class BusinessLayerHandler
{
    public static DataTable unitTable;
    public static DataTable currencyTable;

    private static readonly object unitTableLock = new object();
    private static readonly object currencyTableLock = new object();

    public static DataTable GetUnitList()
    {
        //import lists each time the application is run
        lock(unitTableLock)
        {
            if (unitTable == null)
            {
                unitTable = DatabaseHandler.GetUnitList();
            }
        }

        return unitTable;
    }

    public static DataTable GetCurrencyList()
    {
        //import lists each time the application is run
        lock(currencyTableLock)
        {
            if (currencyTable == null)
            {
                currencyTable = DatabaseHandler.GetCurrencyList();
            }
        }

        return currencyTable;
    }
}

이 룩업에서 정말로 높은 성능이 필요한 경우 매번 전체 잠금 대신 ReaderWriterLockSlim 클래스를 사용하여 응용 프로그램에서 발생하는 대기 횟수를 제한할 수 있습니다.

http://kenegozi.com/blog/2010/08/15/readerwriterlockslim-vs-lock 에서 잠금과 ReaderWriterLockSlim의 차이점에 대한 짧은 기사를 확인하십시오.

편집: (아래 설명에 대한 답변)

unitTableLock 개체는 의 모니터 클래스가 동기화할 핸들처럼 사용됩니다.

의 판독 및 동기화에 대한 전체 개요를 확인할 수 있습니다.NET 프레임워크 이 매우 광범위한 튜토리얼 http://www.albahari.com/threading/ 을 소개합니다.

언급URL : https://stackoverflow.com/questions/6941181/are-static-variables-thread-safe-c-sharp

반응형