2014-09-26 6 views
2

를 삽입 찾기 조작을 보호하고 키/값을 삽입해야하는 경우에만 고유 잠금으로 업그레이드하십시오. 여태까지는 그런대로 잘됐다?혼란 표준에 업그레이드 잠금을 사용하여 이상 : 그, 상대적으로 간단한 형태로 스레드 안전 게터 방법을 고려 /의 찾을지도

은 내가 상상하는 것은 (모든 단계에서 내 개념이 잘못되면 알려 주시기 바랍니다) 다음이다 :

  1. 두 스레드 모두가에 대한 repo.find()을 실행할 수있는

  2. 방법을 입력 같은 시간에 같은 키를 (그리고 키가 존재하지 않습니다).

  3. 두 가지 모두 실패합니다. 키가 존재하지 않습니다. 스레드가 업그레이드 된 지역을 입력 기다리는 동안

  4. 스레드, 업그레이드 된 지역을 입력하여 단독 액세스를 얻을 수 있습니다.

  5. 첫 번째 스레드가 key에 대한 새 항목을 작성한 다음 이 해제됩니다.

  6. 초 스레드가 입력하고 첫 번째 스레드에 의해 삽입 된 키/값을 덮어 씁니다.

우리가 어떻게이 문제를 해결합니까 (사람이 원하는 것을하지 않은)? 감사합니다.

답변

1

요약하면 현재 솔루션에는 거의 아무런 문제가 없습니다.

우선, 두 번째 스레드는 첫 번째 스레드가 쓴 데이터를 덮어 쓰지 않습니다. map::insert()은 새 키만 삽입하기 때문입니다. insert이 요소를 실제로 삽입했는지 확인하고 해당 값을 반환하면됩니다.

아무런 걱정없이 t을 원하지 않는 경우가 있습니다. 이 경우 잠금 후 다른 수표를 추가 할 수 있습니다.

std::map<std::string, boost::shared_ptr<AAA> >::iterator it = repo.find(key); 
if(it == repo.end()){  
    boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock); 
    if (repo.find(key) == repo.end() { 
     ... 
    } 
} 

그러나이 방법이 이점을 제공하는지 확인하려면 코드를 프로파일 링해야합니다.

또한, 당신은 키를 두 번 검색을 피하기 위해 힌트와 함께 map::insert()을 이용할 수있다 : 도움을

std::map<std::string, boost::shared_ptr<AAA> >::iterator it = repo.find(key); 
if(it == repo.end()){  
    boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock); 
    it = repo.lower_bound(key); 
    if (it->first != key) 
     boost::shared_ptr<AAA> t(new AAA(key)); 
     repo.insert(it, std::make_pair(key,t)); 
     return *t;   
    } else { 
     return *it->second; 
    } 
} 
+0

감사합니다. BTW는 두 번째 옵션처럼'lower_bound'와'find' 둘 다 로그 시간 복잡성을 가지고 있습니다. 그러면 그들은 같은 시간이 걸릴 것입니다. ? – rahman

+1

@rahman'insert' 호출을 변경하는 것을 잊어 버렸습니다. 업데이트를 확인하십시오. iterator를 힌트로 취하고이 경우에는 O (1) amortized complexity가있다 (표준의 표 102 참조,'emplace_hint'를 보라). –