idisposable의 스레드 안전 단일 인스턴스를 만드는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/1624226

문제

내 웹 애플리케이션에 필요한이 DB 연결과 같은 객체가 있습니다. 생성하는 것은 매우 느리고 드물게 사용될 것이므로 단일 인스턴스 만 유지하고 싶습니다. 여러 요청에 동시에 필요한 경우 lock() 객체와 접근을 직렬화합니다.

물건을 더 재미있게 만들기 위해 물건은 edisposable이며 닫을 수 있습니다. 당연히, 나는 그것을 닫는 코드를 쓰는 것을 피할 것입니다. 그러나 당신은 ... 죄송합니다 ... 죄송합니다.

따라서 순진한 접근 방식은 다음과 같이 구현하는 것입니다.

private static DBClass _Instance;
private static object _DBLock = new object();

public DBClass GetDB()
{
    if ( _Instance == null )
        lock (_DBLock )
            if ( _Instance == null )
                _Instance = CreateInstance();
    lock (_Instance)
        if ( _Instance.Disposed )
            _Instance = CreateInstance();
    return _Instance;
}

그런 다음 다음과 같이 사용됩니다.

lock (var Conn = Global.GetDB() )
{
    // Use Conn here.
}

이것은 아마도 대부분의 시간에 작동하지만 악용 될 수있는 오프닝이 보입니다. Dispose() 다른 사람이 a lock() 그 위에. 따라서 - 나중에 코드가 실패합니다. 확인 Disposed 그것을 사용하는 모든 장소에서도 어색해 보입니다. 사실로, lock()그것도 어색해 보이지만 인스턴스는 본질적으로 스레드 안전하지 않으므로 내가 할 수있는 일은 없습니다.

이것을 어떻게 구현 하시겠습니까?

도움이 되었습니까?

해결책

처음에는 두 번 확인 된 잠금을 피하는 것이 좋습니다. 이 경우에 한 것처럼 변수를 휘발성하지 않으면 서 잘못 이해하기가 매우 쉽습니다.

당신이 원하지 않는다는 것을 감안할 때 실제로 객체를 처리하십시오. 동일한 API를 구현하는 것이 아니라 처분을 노출시키지 않고 랩핑하지 않는 이유가 있습니까? 이렇게하면 실제로 객체를 사용하는 방식에 따라 잠재적으로 잠금을 캡슐화 할 수 있습니다. 이 작업을 수행하는 또 다른 방법은 Action<DBClass> - 당신은 당신이 객체와 함께 취하고 싶은 행동을 전달하고, 도우미는 인스턴스를 만들고 적절하게 잠금을 처리합니다.

마지막 요점 :이 모든 것이 테스트 가능성 측면에서 다소 까다로워집니다. 나는 당신이 단위 테스트 등의 팬인지는 모르겠지만, 싱글 톤은 종종 테스트를 위해 인생을 다소 어색하게 만듭니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top