2011-04-23 4 views
1

스레드 안전을 위해 Objective-C 클래스를 작성했습니다. 이렇게하려면 pthread와 pthread_rwlock을 사용하고 있습니다 (@synchronized을 사용하면 잔인하며 pthread에 대해 더 자세히 배우고 싶습니다). 자물쇠는 init 메서드로 지정된 객체에 삽입되고 dealloc으로 파괴됩니다. 자물쇠를 조작하는 세 가지 방법이 있습니다. readLock, writeLock, unlock. 이 세 가지 메소드는 단순히 관련 pthread 함수를 호출하고 현재는 다른 것을 호출하지 않습니다. setAddValue: 먼저 기입 로크를 획득하고 또한 기록 잠금을 획득하려고 시도 setValue:atIndex:를 호출 호출스레드에 잠금이 있는지 어떻게 결정합니까?

-(void)addValue:(const void *)buffer 
{ 
    [self writeLock]; 

    NSUInteger lastIndex = self.lastIndex; 
    [self setValue:buffer atIndex:(lastIndex == NSNotFound) ? 0 : lastIndex+1]; 

    [self unlock]; 
} 


-(void)setValue:(const void *)buffer atIndex:(NSUInteger)index 
{ 
    [self writeLock]; 
    //do work here 
    [self unlock]; 
} 

:

여기 writeLock를 필요할 둘 오브젝트 방법, 두 가지이다. 설명서에는이 문제가 발생할 때 동작이 정의되지 않았 음이 나와 있습니다. 따라서, 잠금을 얻으려고 시도하기 전에 스레드에 잠금이 있는지 확인하려면 어떻게해야합니까?

(중요한 섹션이 다른 잠금 요청을 트리거하는 호출을하지 않도록 할 수는 있지만 코드 반복을 의미하므로 코드를 DRY 상태로 유지하고 싶습니다.)

답변

2

사용중인 잠금 장치의 종류를 완전히 밝히지 않았습니다. 당신은 pthread를 사용하고 있고, 읽기/쓰기 잠금을하고 있음을 나타내므로, pthread_rwlock을 사용하고 있다고 결론을 내리고 있습니다.

사실이라면 자물쇠에 pthread_rwlock_trywrlock을 사용할 수 있어야합니다. 매뉴얼 페이지에서

성공하면 pthread_rwlock_wrlock() 및 pthread_rwlock_trywrlock() 함수가 0을 반환합니다. 그렇지 않으면 오류 번호가 으로 표시되어 오류를 나타냅니다. 오류의

그리고, 하나는 다음과 같습니다

는 [EDEADLK] 호출 스레드가 이미 읽기/ (읽기 또는 쓰기에 대해) 쓰기 잠금 소유하고있다.

그러므로, 나는 당신이 pthread_rwlock_trywrlock()를 호출 할 수 있어야 믿고 당신도 성공할 수, 다른 스레드가 잠금이있는 경우가 EBUSY을 반환하거나 현재 스레드가 잠금 장치가있는 경우 당신은 EDEADLK을 얻을 것이다.

+0

이 정보는 약간 정확합니다. 'EDEADLK' 에러는'pthread_rwlock_ (rd | wr) lock'에 대해서만 지정되며,이 경우에는'EBUSY'를 리턴하고 호출 스레드 나 다른 스레드에 의해 잠금이 유지되는지를 구분하지 않는 trylock 함수가 아닙니다. 또한 같은 스레드가 보유하고있는 잠금은 쓰기 잠금 일 때만 감지 할 수 있습니다. 무제한의 독자가있을 수 있으므로 잠금을 보유한 독자의 신원을 확인할 수 없습니다. 그러나 OP의 경우에는 이중 쓰기 잠금처럼 보이는 것이 피할 필요가 있으므로 문제는 아닙니다. –

+0

또한 'EDEADLK' 오류는'할 수 있습니다. '가 아니라'할 수 있습니다. '즉 구현을 감지하고보고 할 필요가 없습니다. –

+0

추가 고려 사항에서 나는 당신의 솔루션이 작동한다고 생각하지 않습니다. 답변으로 대안을 게시했습니다. –

0

먼저, 단 하나의 연산 만 포함하는 임계 섹션은 쓸모가 없습니다. 요점은 서로 다른 것들을 서로 동기화하는 것입니다. (당신은 효과적으로 정수를 원자 적으로 만들지 만 그것은 완전한 의도는 아닐 것입니다.)

둘째, 당신은 이미 후자의 중요한 섹션 안에 쓰기 잠금이 있다는 것을 이미 알고 있기 때문에 그것이 존재하는지 또는 확인할 필요가 없습니다. 아니. 쓰는 동안 읽기 잠금을 시도하지 마십시오.

해결 방법은 아마도 readLockwriteLock 호출을 호출하는 함수로 호출하는 것이지만 더 이상 말할 수는 없습니다.

(이 또한 가능성, 전체 작업의 수를 줄일 수는 고정되지 않으므로 다음 즉시 풀어 잠금의 성능 비용을 줄일 수 있습니다. 아마 당신은의 pthreads 수준에서 직접 작업 할 필요가 없습니다.)

+0

첫 번째 문장은 매우 위험합니다. C에서 단일 원자 연산과 같은 것은 존재하지 않습니다. x86 어셈블리를 작성하고 'lock' 접두어가 붙은 메모리 - 피연산자 명령어를 사용한다면 정확할 것입니다. 그렇지 않으면 잠금이 필요합니다. –

+0

@R .. : 나는 그가하고있는 잠금의 효과는 정수를 원자 적으로 만드는 것이라고 말하고있다. 적어도 그 사람이하고있는 것. 내 대답을 쓴 이후 질문이 바뀌 었습니다. (또 다른 대답을 받아 들여 이상하게도) – Potatoswatter

0

이식 가능한 프로그램은 호출자에게 이미 쓰기 잠금을 보유하고 있음을 알리기 위해 구현에 의존 할 수 없습니다. 대신 재귀 쓰기 잠금 rwlocks에 포장 같은 것을 할 필요가 :이 저장된 곳

int wrlock_wrap(pthread_rwlock_t *l, int *cnt) 
{ 
    int r = *cnt ? 0 : pthread_rwlock_wrlocK(l); 
    if (!r) ++*cnt; 
    return r; 
} 

int wrunlock_wrap(pthread_rwlock_t *l, int *cnt) 
{ 
    --*cnt; 
    return pthread_rwlock_unlock(l); 
} 

당신은 pthread_rwlock_t 옆의 수를 유지할 수 있습니다, 예를 들어, 귀하의 구조체/클래스/뭐든의 구성원으로.

+0

당신의 이식성에 대한 쪽지는 정확하지만, OP는 OS X에 명확하게 나와 있으며, Objective C 및 Cocoa 프레임 워크 중 선택에 따라 이식성 고려 사항을 포기했습니다. 원래는 OP와 동일한 구현체를 제안했지만 OS X 맨 페이지 (위 참조)를 확인한 후 중단했습니다. –

관련 문제