문제

나는 Mike Ash "Singletons의 Care and Feeding"에 이것을 쫓아 냈고 그의 의견에 약간의 당황했다.

그러나이 코드는 속도가 느립니다. 자물쇠를 가져가는 것은 다소 비싸다. 더 고통스럽게 만드는 것은 대부분의 시간이 대부분의 자물쇠가 무의미하다는 사실입니다. 자물쇠는 foo가 nil 일 때만 필요합니다. 기본적으로 한 번만 발생합니다. 싱글 톤이 초기화 된 후에는 잠금의 필요성이 사라졌지 만 잠금 자체는 남아 있습니다.

+(id)sharedFoo {
    static Foo *foo = nil;
    @synchronized([Foo class]) {
        if(!foo) foo = [[self alloc] init];
    }
    return foo;
}

내 질문은 의심 할 여지가 없다는 것이 의심의 여지가 없지만 FOO가 NIL 일 때 자물쇠를 제한하기 위해 왜 (아래 참조) 글을 쓸 수없는 이유는 무엇입니까?

+(id)sharedFoo {
    static Foo *foo = nil;
    if(!foo) {
        @synchronized([Foo class]) {
            foo = [[self alloc] init];
        }
    }
    return foo;
}

게리를 건배합니다

도움이 되었습니까?

해결책

그렇다면 시험은 인종 조건에 따라 달라지기 때문입니다. 두 개의 다른 스레드가 독립적으로 테스트 할 수 있습니다 foo ~이다 nil, 그런 다음 (순차적으로) 별도의 인스턴스를 만듭니다. 한 스레드가 테스트를 수행하는 동안 다른 스레드가 여전히 내부에있을 때 수정 된 버전에서 발생할 수 있습니다. +[Foo alloc] 또는 -[Foo init], 아직 설정되지 않았습니다 foo.

그건 그렇고, 나는 그렇게하지 않을 것입니다. 확인하십시오 dispatch_once() 기능, 블록이 앱의 수명 동안 한 번만 실행되도록 보장 할 수 있습니다 (타겟팅하는 플랫폼에 GCD가 있다고 가정).

다른 팁

이것을 이중 점검 잠금 "최적화". 어디에서나 문서화 된 바와 같이 이것은 안전하지 않습니다. 컴파일러 최적화로 패배하지 않더라도 펜스/장벽을 사용하지 않는 한 현대 머신에서 메모리가 작동하는 방식을 패배하게됩니다.

Mike Ash도 보여줍니다 사용하는 올바른 솔루션 volatile 그리고 OSMemoryBarrier();.

문제는 하나의 스레드가 실행될 때입니다 foo = [[self alloc] init]; 다른 스레드가 볼 때 foo != 0 모든 메모리가 수행 한 글입니다 init 도 보입니다.

또한 참조하십시오 DCL 및 C ++ 그리고 DCL과 Java 자세한 사항은.

귀하의 버전에서 수표 !foo 여러 스레드에서 동시에 발생할 수있어 두 개의 스레드가 alloc 하나는 다른 인스턴스를 할당하기 전에 다른 사람이 완료되기를 기다리고 있습니다.

foo == nil 인 경우 잠금 만 가져 가면 최적화 할 수 있지만 그 후에는 레이스 조건을 보호하기 위해 다시 테스트해야합니다 (@SynChronized 내에서).

+ (id)sharedFoo {
    static Foo *foo = nil;
    if(!foo) {
        @synchronized([Foo class]) {
            if (!foo)  // test again, in case 2 threads doing this at once
                foo = [[self alloc] init];
        }
    }
    return foo;
}

그랜드 캐롤 파견이있는 경우 가장 좋은 방법

+ (MySingleton*) instance {
 static dispatch_once_t _singletonPredicate;
 static MySingleton *_singleton = nil;

 dispatch_once(&_singletonPredicate, ^{
    _singleton = [[super allocWithZone:nil] init];
 });

 return _singleton
 }
+ (id) allocWithZone:(NSZone *)zone {
  return [self instance];
 }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top