2011-07-03 1 views
2

프로그래밍 기술이나 디자인과 관련하여 질문이 있지만 제안이 열려 있는지 잘 모르겠습니다.C++/Boost : 여러 메서드 (게터) 호출을 통해 리소스에 대한 액세스를 동기화합니다.

문제 : 데이터 소스 (센서)와 소비자간에 추상화 계층을 만들고 싶습니다. 아이디어는 소비자가 다른 센서 유형의 인터페이스 (추상 기본 클래스) 만 "알고"있다는 것입니다. 이 센서 유형은 대개 고유 한 게터 메소드가있는 여러 개별 값으로 구성됩니다.

예를 들어 간략화 된 GPS 센서를 사용합니다. 센서에 대한 업데이트가 다른 스레드에 의해 수행되기 때문에

class IGpsSensor { 

    public: 
     virtual float getLongitude() = 0; 
     virtual float getLatitude() = 0; 
     virtual float getElevation() = 0; 

     // Deviations 
     virtual float getLongitudeDev() = 0; 
     virtual float getLatitudeDev() = 0; 
     virtual float getElevationDev() = 0; 

     virtual int getNumOfSatellites() = 0; 
}; 

일관성을 보장하기 위해 합리적인 방법처럼 보인다 게터 또한 업데이트 방법을 동기화 (세부 사항은 인터페이스의 구현에있다).

지금까지 그렇게 좋았습니다. 대부분의 경우이 수준의 동기화로 충분합니다. 그러나 때로는 연속적인 getXXX() 호출로 하나 이상의 값을 얻고 그 사이에 아무런 업데이트도 일어나지 않을 수도 있습니다. 이것이 필요한지 아닌지 (그리고 어떤 값이 중요한지) 여부는 소비자의 몫입니다.

많은 경우에 위도와 경도를 아는 것이 중요합니다 (그러나 둘 다 동일한 업데이트()와 관련이 있습니다). 나는 이것을 "위치"클래스 또는 구조체로 그룹화하는 것이 가능하다는 것을 인정합니다. 그러나 소비자는 더 복잡한 알고리즘을 위해 센서를 사용할 수도 있고 편차가 필요할 수도 있습니다.

지금이 작업을 수행하는 데 올바른 방법이 무엇인지 궁금합니다. 내가 생각할 수

솔루션 : 구조체 (또는 클래스)에

  • 그룹 가능한 모든 값을 한 번에 모든 값의 복사본을 반환 추가 (동기화) 게터를 추가 - 불필요한 많은 것 같아 오버 헤드는 나에게 단지 2 또는 3 아마 10 값 중 필요합니다.

  • 소비자가 잠금을 허용하기 위해 데이터 소스 내에서 사용 된 뮤텍스에 대한 참조를 반환하는 메소드를 추가합니다. 이는 "좋은 디자인"처럼 느껴지지 않습니다. 그리고 getter가 이미 동기화되었으므로 재귀 적 뮤텍스를 사용해야합니다. 그러나 여러 독자가 있지만 단 한 명의 작가가 있다고 가정하므로 여기에 공유 뮤텍스를 사용해야합니다.

도움 주셔서 감사합니다.

+0

나는 당신이 너무 추상적이라고 생각합니다. 우리는 Value1, Value2 및 Value3에 대한 인터페이스를 디자인 할 수 없으며 일부 인터페이스는 때때로 연결될 수 있습니다. 중간 계층 (브로커)이 유용 할 경우, 언제 어떻게해야 하는지를 알아야합니다. –

+0

원래 게시물을 덜 추상적으로 편집했습니다. 값에는 연결이 있지만 브로커는 소비자가 실제로 필요로하는 값을 알지 못합니다. – rocktale

답변

1

가능한 해결 방법 : 당신은/endTransaction을 방법을 시작, 여러 값을 읽어 사용해야하는 경우

class Transaction { 
    pthread_mutex_t mtx; 
    // constructor/destructor 
public: 
    void beginTransaction() { pthread_mutex_lock(&mtx); } // ERROR CHECKING MISSING 
    void endTransaction() { pthread_mutex_unlock(&mtx); } // DO ERROR CHECKING 
protected: 
    // helper method 
    int getSingle(int *ptr) 
    { int v; beginTransaction(); v=*ptr; endTransaction(); return v; } 
}; 

에서 모든 소스 클래스를 파생. getValue 함수를 정의하려면 getSingle을 적절한 멤버에 대한 포인터와 함께 호출하면됩니다. 이는 각 getValue 함수에서 begin/endTransaction을 호출 할 필요가 없도록 편리한 메소드입니다.

getValue 함수가 begin/endTransaction을 사용하면 트랜잭션 내에서 호출 할 수 없으므로 일부 세부 사항을 자세히 설명해야합니다. (뮤텍스는 재귀 적으로 구성되지 않는 한 한 번만 잠글 수 있습니다.)

+0

아이디어를 제공해 주셔서 감사합니다. 내 생각에, 뮤텍스 자체를 "전달"하는 것과 본질적으로 같지만 mutex를 사용하면 소비자가 boost RAop 스타일을 얻기 위해 boost의 scoped_lock과 같은 것을 사용할 수 있습니다. 원래 게시물에서 말했듯이 recursive_lock을 사용하면 shared_lock을 여러 개의 리더/단일 라이터 액세스에 사용하지 못하게됩니다. – rocktale

2

"리더"인터페이스를 노출하는 방법은 어떻습니까?

const IGpsSensorReader& gps_reader = gps_sensor.getReader(); 

IGpsSensorReader 클래스는 IGpsSensor 클래스의 보호 된 멤버에 액세스 할 수 있습니다 : 독자 객체를 얻으려면, 당신은 이런 식으로 뭔가를 할 것입니다. 구성되면 잠금을 획득합니다. 파괴되면, 자물쇠가 풀릴 것입니다. 접근자는 다음과 같이 할 수 있습니다.

{ //block that accesses attributes 
    const IGpsSensorReader& gps_reader = gps_sensor.getReader(); 
    //read whatever values from gps_reader it needs 
} //closing the scope will destruct gps_reader, causing an unlock 

또한 업데이트를 수행하는 스레드에 getWriter 메소드를 노출 할 수 있습니다. 내부적으로는 부스트의 shared_mutex을 사용하여 독자와 작성자 간의 액세스를 중재 할 수 있습니다.

+0

독자 인터페이스의 아이디어가 마음에 들어요. 그러나 구현에 어려움을 겪고 있습니다. 예제가 작동하려면 getReader()가 값으로 IGpsSensorReader를 반환해야합니다 (나중에 판독기를 파괴하는 임시 참조를 만들려면). 그러나 그것은 작동해서는 안되는 인터페이스이기 때문에. 하지만 어쩌면 여기서 뭔가를 놓치고있어 ... – rocktale

+0

shared_ptr 를 반환하는 방법은 무엇입니까? – jterrace

+1

또는 IGpsSensorReader는 IGpsSensor 참조를 취할 수 있습니다. 'IGpsSensorReader reader (gps_sensor); // 센서를 잠급니다. const float fLongitude = reader.getLongitude();' – pilkch

2

몇 가지 간단한 프로젝트에서 사용한 기술은 프록시 개체에 대한 액세스 만 제공하는 것입니다. 이 프록시 객체는 수명 기간 동안 잠금을 유지하고 내 데이터에 실제 인터페이스를 제공합니다. 이 액세스는 이미 동기화되지 않은 프록시를 통해서만 사용할 수 있기 때문에 동기화 자체를 수행하지 않습니다. 이 프로젝트를 본격적으로 확장하려고 시도한 적이 없지만 제 목적을 위해 잘 작동하는 것으로 보입니다.

관련 문제