동적 메서드 호출을위한 일종의 전화 번호부 역할을하는 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)이라는 오픈 소스 프로젝트의 일부입니다.
다른 코드가 노드를 제거하려고 시도하는 경우에도 첫 번째 해결 방법은 "좋지 않음"입니다. – peterchen
오브젝트를 제거하는 코드가 먼저 루트에서 쓰기 잠금을 요구할 수 있습니다. – gaspard