2012-09-11 6 views
0
public class MyConfigurationData 
{ 
    public double[] Data1 { get; set; } 
    public double[] Data2 { get; set; } 
} 
public class MyClass 
{ 
    private static object SyncObject = new object(); 
    private static MyConfigurationData = null; 
    private static MyClass() 
    { 
     lock(SyncObject) 
     { 
     //Initialize Configuration Data 
     //This operation is bit slow as it needs to query the DB to retreive configuration data 
     } 
    } 
    public static MyMethodWhichNeedsConfigurationData() 
    { 
     lock(SyncObject) 
     { 
      //Multilple threads can call this method 
      //I lock only to an extent where I attempt to read the configuration data 
     } 
    } 
} 

내 응용 프로그램에서는 구성 데이터를 한 번만 만들고 여러 번 여러 번 사용해야합니다. 즉, 한 번 쓰고 여러 번 읽습니다. 또한 필자는 쓰기 작업이 끝날 때까지 읽기가 발생하지 않아야 함을 확신하고자했습니다. 즉, MyConfigurationData를 NULL로 읽으 려하지 않습니다.잠금이없는 정적 구성 데이터를 구현하는 방법이 있습니까?

정적 생성자는 AppDomain에서 한 번만 호출된다는 것을 알고 있습니다. 그러나 구성 데이터를 준비하는 동안 어떤 스레드가이 데이터를 읽으려고하면 어떻게 동기화를 효과적으로 수행 할 수 있습니까? 결국, 필자는 읽기 작업의 성능을 향상시키고 자했습니다.

내 목표를 잠금없이 구현할 수 있습니까?

답변

2

의 데이터를으로 읽는 동안에는 이미 스레드로부터 안전해야합니다. 매우 작은 데이터 구조는 이 단지을 읽을 때 스레드로부터 안전하지 않습니다 (명백한 카운터 예제에는 지연로드가 포함될 수 있음). 정적 생성자는 런타임에 의해 자동으로 동기화되므로 "구성 데이터 초기화"단계를 실행하는 여러 스레드에 신경 쓸 필요가 없습니다.

그래서 데이터를 변경하는 것이 없으면 이미 안전합니다. 자물쇠를 제거하면 병렬 처리를 향상 시킨다는

public class MyClass 
{ 
    private static MyConfigurationData; 
    private static MyClass() 
    { 
    //Initialize Configuration Data 
     MyConfigurationData = ... 
    //This operation is bit slow as it needs to query the DB to retreive configuration data 
    } 
    public static MyMethodWhichNeedsConfigurationData() 
    {   //Multilple threads can call this method 
     var config = MyConfigurationData; 

    } 
} 

참고 : 당신은 또한 즉

public class ConfigurationData { 
    // or some similar immutable API... 
    public double GetData1(int index) { return data1[index]; } 
    public double GetData2(int index) { return data2[index]; } 

    private readonly double[] data1, data2; 

    public ConfigurationData(double[] data1, double[] data2) { 
     this.data1 = data1; 
     this.data2 = data2; 
    } 
} 

그런 다음 당신이 어떤 잠금을 필요로하지 않는, 불변의 인터페이스 뒤에 데이터를 숨김으로써 오해하기 어렵게 만들 수; 원시 단일 스레드 성능은 변경되지 않습니다.

그렇습니다 : 나는 정적 데이터에 대해 조언해야합니다 일반적으로; 그것은 테스트하기가 매우 어렵고, 필요가 바뀌면 다중 소유와 같은 일을하는 것이 까다로울 수 있습니다. 의 단일 구성 인스턴스를 가지고 있지만 시스템에 컨텍스트의 일부 양식으로 전달하는 것이 더 바람직 할 수 있습니다. 어느 접근법이 성공적으로 사용될 수 있습니다 - 이것은 알고 있어야 할 것입니다.

+0

설명해 주셔서 감사합니다. – Imran

+0

+1. @Imran, 결과 객체는 기존의 "lock-free"(코드에서 잠금/중요 섹션을 제외하고 똑똑한 코드 조직을 사용하여 대부분의 InterlockedXXXX 작업을 사용하지 않음) 런타임에 필요하지 않습니다. 대부분 likley는 잠금을 사용하여 생성을 직렬화합니다 정적 객체의 –

+0

@AlexeiLevenkov, 알겠습니다. 런타임에서 정적 객체를 만드는 동안 잠금을 사용하면 괜찮습니다. 나는 그 정적 인 객체들에 대한 lock-free 읽기에 대해서만 염려한다. – Imran

4

MSDN에서 :

정적 생성자는 정적 데이터를 초기화하거나 또는 한번만 수행해야하는 특정 작업을 수행하기 위해 사용된다. 첫 번째 인스턴스가 생성되거나 정적 멤버가 참조되기 전에 자동으로 호출됩니다.

코드에서 lock을 사용할 필요가 없으므로 실제로 스레드로부터 안전합니다. 정적 생성자는 MyMethodWhichNeedsConfigurationData이 참조되기 전에 호출됩니다.

public class MyClass 
{ 
    private static MyConfigurationData = null; 
    private static MyClass() 
    { 
    } 

    public static MyMethodWhichNeedsConfigurationData() 
    { 
    } 
} 
+0

감사합니다. 정적 생성자에 대한 내 인식이 올바른지 두 번 확인하고 싶습니다. – Imran

1

난 당신이 싱글 톤 패턴을 사용하여 클래스의 인스턴스를 반환 "하는 GetInstance"방식으로 구성 초기화 로직을 넣어한다고 생각합니다.

이렇게하면 읽기에 잠금 메커니즘이 필요 없습니다.

+0

MyClass의 단일 인스턴스를 만들 필요가 없으므로 내 목표는 Singleton 패턴과 관련이 없습니다. 인스턴스 메서드가 아닌 정적 메서드를 통해 정적 구성 데이터를 처리하려고합니다. – Imran

+0

하지만 "구성 데이터를 한 번만 만들고 여러 번 사용해야합니다." "개인 정적 MyClass()" –