2010-01-21 7 views
1

동적 메서드 호출을위한 일종의 전화 번호부 역할을하는 Root라는 클래스가 있습니다.이 클래스는 개체를 가리키는 URL 키 사전을 보유하고 있습니다. 명령이이 URL과 몇 가지 매개 변수를 사용하여 루트 인스턴스를 호출 주어진 방법을 실행하고자 할 때 : 사실어려운 동시 디자인

root_->call("/some/url", ...); 

을, 루트의 호출 방법이 가까운 같습니다

// Version 0 
const Value call(const Url &url, const Value &val) { 
    // A. find object 
    if (!objects_.get(url.path(), &target)) 
    return ErrorValue(NOT_FOUND_ERROR, url.path()); 
    } 

    // B. trigger the object's method 
    return target->trigger(val); 
} 

을 코드에서 위의 "호출"방법은 이 아니며 스레드 안전 : "대상"개체는 A와 B 사이에서 삭제 될 수 있으며 우리는 "objects_"멤버 (사전)가 읽지 않은 동안에는 변경되지 않는다고 보장하지 않습니다 그것. 나에게 발생

첫 번째 솔루션이었다

// Version I 
const Value call(const Url &url, const Value &val) { 
    // Lock Root object with a mutex 
    ScopedLock lock(mutex_); 

    // A. find object 
    if (!objects_.get(url.path(), &target)) 
    return ErrorValue(NOT_FOUND_ERROR, url.path()); 
    } 

    // B. trigger the object's method 
    return target->trigger(val); 
} 

이 "target-> 트리거 (발)"까지 괜찮 루트 변경해야하는 방법, 두 객체의 URL을 변경하거나으로 새 개체 삽입 범위를 수정하고 도움을 줄 수있는 RW 뮤텍스를 사용하여 (훨씬 더 루트에 쓰기보다 읽기가) :

// Version II 
const Value call(const Url &url, const Value &val) { 
    // A. find object 
    { 
    // Use a RW lock with smaller scope 
    ScopedRead lock(mutex_); 
    if (!objects_.get(url.path(), &target)) 
     return ErrorValue(NOT_FOUND_ERROR, url.path()); 
    } 
    } 
    // ? What happens to 'target' here ? 

    // B. trigger the object's method 
    return target->trigger(val); 
} 

무슨 일이 '대상'은 어떻게됩니까? 우리는 그것이 발견과 부름 사이에서 삭제되지 않도록 어떻게 보장합니까?

몇 가지 아이디어 : 개체 삭제는 루트의 메시지 대기열에 게시 후 처리 될 수 있습니다. 그런 다음 전체 메소드 범위에서 다른 RW 뮤텍스 읽기 잠금 삭제가 필요하며 삭제 대기열을 처리하기 위해 별도의 스레드를 사용해야합니다.

이 모든 것이 나에게 너무 복잡해 보입니다. 동시 디자인이 이와 같이 보일 것인지 아니면 올바른 아이디어가 없는지 확실하지 않습니다.

추신 :이 코드는 oscit (OpenSoundControl it)이라는 오픈 소스 프로젝트의 일부입니다.

+0

다른 코드가 노드를 제거하려고 시도하는 경우에도 첫 번째 해결 방법은 "좋지 않음"입니다. – peterchen

+0

오브젝트를 제거하는 코드가 먼저 루트에서 쓰기 잠금을 요구할 수 있습니다. – gaspard

답변

2

'대상'의 삭제를 피하려면 스레드 안전 참조 카운트 된 스마트 포인터을 작성해야했습니다. 그렇게하기가 어렵지 않습니다. 중요한 부분 내에서 참조 횟수에 액세스해야한다는 것을 보장해야합니다. 자세한 내용은 this post을 참조하십시오.

+0

좋은 생각입니다. 난 그냥 --ref_count와 unregister 명령을 처리해야한다. 먼저 등록을 취소하고 (읽기 잠금은 이것을 막을 것이다), --ref_count (증가 된 ref_count는 삭제를 방지한다). – gaspard

+0

쓰레드 안전 참조 된 스마트 포인터를 쓰는 것이 어렵지 않을 것이라고 생각한다면, 스마트 포인터를 향상시킨 개발자와 이야기하고 정상적인 스마트 포인터를 구현하는 데있어 모든 문제가 무엇인지 질문해야합니다. –

+0

스마트 포인터 의미론이 필요하지 않습니다. (어쨌든 피하는 경향이 있습니다.) 요점은 스레드 안전 참조 계산입니다. – gaspard

1

이 트랙은 잘못된 것입니다. 주의 : 데이터를 잠글 수 없으며 코드 만 차단할 수 있습니다. 로컬로 정의 된 뮤텍스로 "개체"멤버를 보호 할 수 없습니다. 객체 컬렉션을 변경하는 코드에는 정확히 동일한 뮤텍스가 필요합니다. 다른 스레드가 call() 메서드를 실행할 때 코드를 차단해야합니다. 뮤텍스는 최소한 클래스 범위에서 정의되어야합니다.

+0

"데이터 잠그기"는 "중요한 섹션 내에서 데이터 액세스"로 이해합니다. 이는 일반적인 관행입니다. –

+0

예, CS도 작동합니다. 여전히 함수에 국한된 것은 될 수 없으며 "객체"를 변경하는 코드는 동일한 것을 사용해야합니다. –

+0

흠, 로컬로 정의 된 뮤텍스가 표시되지 않습니다. "mutex_"는 클래스 멤버이고 ScopedRead는 "mutex_"를 잠그는 범위가 지정된 잠금입니다. 이 코드에는 뮤텍스 인스턴스가 없습니다. 내가 뭐 놓친 거 없니 ? – gaspard