2013-03-21 1 views
3

우리의 응용 프로그램에서는 작업 스레드에서 처리되고 표시 스레드에서 액세스되는 데이터를 처리하며 중요한 섹션을 처리하는 뮤텍스가 있습니다. 특별한 것은 없습니다.Guarded Data Design Pattern

이제 우리는 현재 잠금을 데이터 보유 및 처리 당사자가 명시 적으로 수행하는 코드를 다시 작업하는 방법에 대해 생각했습니다. 우리는 데이터를 보유하고 데이터에 대한 액세스 권한을 보호하는 단일 엔터티를 생각했습니다.

이를 위해 GuardedData라는 클래스가 있습니다. 호출자는 이러한 객체를 요청할 수 있으며 로컬 범위에서 잠시 동안 만 객체를 유지해야합니다. 객체가 살아있는 한 잠금을 유지합니다. 객체가 파괴 되 자마자 잠금 장치가 해제됩니다. 데이터 액세스는 호출자의 명시적인 추가 작업없이 잠금 메커니즘과 결합됩니다. 학급의 이름은 현재 경비병의 호출자를 상기시킨다.

template<typename T, typename Lockable> 
class GuardedData { 
    GuardedData(T &d, Lockable &m) : data(d), guard(m) {} 
    boost::lock_guard<Lockable> guard; 
    T &data; 

    T &operator->() { return data; } 
}; 

다시 말하면 매우 간단한 개념입니다. 연산자 -> 페이로드에 액세스하기 위해 STL 반복기의 의미를 모방합니다.

지금 궁금 :

  • 이 방법인가 잘 알려진?
  • 이미 사용 가능한 템플릿 클래스가 있습니까? 예 : 부스트 라이브러리에?

나는 그것이 상당히 일반적이며 유용한 개념이라고 생각하기 때문에 묻습니다. 나는 그것을 좋아하지 않는 무엇이라도 발견 할 수 없었다.

+1

포 그라운드에서 액세스되는 동안 백그라운드에서 변경할 수있는 데이터가 있습니다. 효과적으로 배경 계산이 끝나면 데이터가 바뀝니다. 이 스왑은 누군가가 데이터에 액세스하는 동안 발생해서는 안되며, 이로 인해 해당 당사자가 일관성없는 상태가 될 수 있습니다. 새 인스턴스를 만드는 대신 스왑을 수행해야하지만 다른 인스턴스는 여전히 이전 인스턴스를 사용합니다. 그 이유는 엄청난 양의 데이터가 동시에 메모리에 상주하기 때문입니다. – ypnos

답변

1

잘 알려져 있습니다. 확실하지 않습니다. 그러나 Qt에서 종종 비슷한 메커니즘을 사용합니다 (QMutexLocker). 구별 (미성년자, imho)은 뮤텍스와 함께 데이터를 바인딩한다는 것입니다. 설명했던 것과 매우 유사한 메커니즘이 C#의 스레드 동기화 표준입니다.

한 번에 하나의 데이터 항목을 지키기위한 접근 방법은 좋지만 그 이상을 감시해야하는 경우 성가신 방법입니다. 또한, 당신의 설계가 공유 된 장소에서이 객체를 생성하지 못하게하고, 제발 내가 원하는만큼 데이터에 액세스하는 것을 멈추게 할 것입니다. 그러나 실제로 재귀 액세스 시나리오는 처리되지 않으며, 그렇지 않습니다. 다중 스레드 액세스 시나리오가 동일한 범위에서 발생하는 경우

아이디어가 약간 끊어지는 것 같습니다. 데이터를 보호하기 때문에 항상 데이터에 액세스하는 것은 스레드로부터 안전하다는 것을 의미합니다. 종종 이것은 스레드 안전을 보장하기에 충분하지 않습니다. 보호 된 데이터에 대한 연산 순서는 중요하므로 잠금은 데이터 지향적 인 것이 아니라 범위 지향적입니다. 더미 객체를 지키고 가비지 객체를 임시 범위로 래핑하여 모델에서이 문제를 해결할 수 있지만 기존 뮤텍스 구현을 사용하지 않는 이유는 무엇입니까?

정말 나쁜 접근 방법은 아니지만 의도 된 용도를 이해해야합니다.

+0

나는 QMutexLocker가 boost :: lock_guard와 똑같다고 생각한다. 그것들은 mutex aquire/release에 대한 RAII/RRID 래퍼입니다. – Pete

2

사용 방법에 따라 교착 상태가 발생할 수 있습니다. 2 개의 데이터를 처리하려면 뮤텍스를 두 번 잠금 처리하고 교착 상태가됩니다 (각 데이터에 자체 뮤텍스가 없으면 잠금 순서가 일관되지 않으면 교착 상태가 발생합니다). 그게 정말 복잡하지 않고이 제도와 함께). 원하지 않을 수도있는 재귀 뮤텍스를 사용하지 않는 한.

또한 GuardedData 객체는 어떻게 전달됩니까?boost :: lock_guard는 복사 할 수 없습니다. 뮤텍스에 대한 소유권 문제가 발생합니다 (예 : &).

중요한 섹션을 짧게 유지하면서 필요할 때마다 리더/라이터 스레드에 필요한 데이터의 일부를 복사하는 것이 더 쉽습니다. 작성자는 마찬가지로 한 번에 데이터 모델을 커밋합니다.

기본적으로 뷰어 스레드는 주어진 시간에 필요한 데이터의 스냅 샷을 가져옵니다. 이것은 심지어 스레드를 실행하는 코어 근처에있는 CPU 캐시에 완전히 맞을 수 있으며 RAM에 저장하지 않을 수도 있습니다. 작성자 스레드는 독자가 처리하는 동안 기본 데이터를 수정할 수 있습니다 (단, 뷰는 무효화되어야합니다). 그러나 뷰어에는 복사본이 있으므로 데이터와 동기화 된 순간에 데이터 뷰를 계속 제공 할 수 있습니다.

다른 옵션은 뷰에 데이터에 대한 스마트 포인터 (불변으로 처리되어야 함)를 제공하는 것입니다. 작성자가 데이터를 수정하려면 해당 시점에 복사 한 후 복사본을 수정하고 완료되면 포인터를 모델의 데이터로 전환합니다. 이렇게하면 작가가 하나만있는 경우가 아니면 처리하는 동안 모든 리더/라이터를 차단해야합니다. 다음에 독자가 데이터를 요청하면 새로운 사본이 생성됩니다.

+0

그래서 두 번째 반복은 lock_guard 대신 boost :: recursive_mutex를 사용하는 것입니다. – ypnos

+0

해당 데이터 개체는 수 기가 바이트에 이르기 때문에 중복 복사본을 피하는 것이 중요합니다. – ypnos

+0

매번 모든 데이터를 복사해야합니까? 외부 클라이언트가 잠금을 관리하도록 허용하면 문제가 발생할 가능성이 높습니다. – Pete