2010-04-19 3 views
6

스레드 안전 컬렉션 (ThingList라고 함)이 있다고 가정하고 다음 함수를 추가하고 싶습니다. 객체를 것이다 해제/분명히스레드로부터 안전한 방법으로 포인터 반환

try 
{ 
    list.lock(); // NEEDED FOR THREAD SAFETY 
    Thing *foo = list.findByName("wibble"); 
    foo->Bar = 123; 
    list.unlock(); 
} 
catch (...) 
{ 
    list.unlock(); 
    throw; 
} 

RAII 잠금 :

Thing * ThingList::findByName(string name) 
{ 
    return &item[name]; // or something similar.. 
} 

그러나 이렇게

, 나는 이런 식으로 뭔가를해야 할 것입니다 호출 코드에 대한 스레드 안전에 대한 책임을 위임했습니다 try/catch/unlocks를 단순화/제거 할 수 있지만 호출자가 잊어 버리기는 쉽습니다.

내가 검토 한 결과 몇 가지 대안이 있습니다 대신 포인터의 값으로

  • 반환 살아라 - 당신이 필요하지 않는 한 잘
  • 기능 ThingList::setItemBar(string name, int value)를 추가 것 수정 - 좋은, 그러나 이들은 경향이 있습니다 proliferate
  • 생성시 목록을 잠그고 파기시 다시 잠금을 해제하는 포인터와 같은 객체를 반환합니다. 이것이 좋은지 나쁜지 잘 모르겠다면 ...

이 문제를 해결하는 올바른 방법은 무엇입니까?

답변

4

'올바른 접근 방식'이 없습니다. 그것은 당신의 어플리케이션의 요구에 달려 있습니다.

가능하면 값으로 값을 반환하거나 호출자가 원하는대로 수행 할 수있는 복사본을 반환하십시오.

위의 변형은 수정 가능한 복사본을 반환 한 다음 수정 된 개체를 원자 적으로 목록에 다시 병합하는 방법을 제공합니다. 예 :

Thing t = myThingList.getThing(key); 
t.setFoo(f); 
t.setBar(b); 
myThingList.merge(t);  // ThingList atomically updates the appropriate element 

그러나 여러 스레드가 동일한 개체를 업데이트하려고하면 문제가 발생할 수 있습니다.

"포인터와 같은 객체"아이디어는 멋지지만 어떤 잠금 장치가 어딘가에 릴리스되지 않을 때 찾기 힘든 버그로 이어질 것이라고 생각합니다.

나는 모든 잠금/잠금 해제 코드를 ThingList 내에 유지하려고하므로 ThingList::set... 기능이 아마도 내가하는 일일 것입니다.

+0

이 좋다 "병합"잠금 해제 후 안전하지만 것은 객체가 알고있는 숨겨진 가정이있다 방법 목록에 자신을 찾습니다. 병합하기 위해 "키"를 전달할 수는 있지만 삭제 된 항목을 병합하는 문제가 있습니다. – Roddy

3

저장 및 반환 부스트 :: shared_ptr의의

당신은 액세스하는 동안 고정해야하지만 당신은

+1

boost :: shared_ptr은 컬렉션의 스레드 안전을 보호하기 위해 아무 작업도 수행하지 않습니다. –

+0

당신이 처리하려고하는 스레드 안전 문제에 따라 달라집니다. 컬렉션에 액세스 할 때 (읽기 또는 쓰기) 잠글 필요가 있지만 어쨌든 그렇게해야합니다. 공유 된 ptr을 반환하면 최소한 콜렉션이 변경된 후에도 콜렉션이 여전히 shared_ptrs의 콜렉션이라고 가정하면 여전히 OK입니다. 이것은 많이 쓰레드가 많은 서버에서 항상 사용하는 모델입니다. – pm100

+0

shared_ptr이 쓰레드 안전하다고는 몰랐습니다. 그러나 그것에 대해 생각할 필요는 없습니다.Microsoft의 COM은 InterlockedIncrement와 InterlockedDecrement를 사용하여 매우 가벼운 스레드 안전 구현을 수행한다는 것을 알고 있습니다. –

관련 문제