2012-11-09 3 views
6

스레드 안전 개념을 이해합니다. 단일 변수를 보호하려고 할 때 스레드 안전을 단순화하는 조언을 찾고 있습니다. 스레드 안전성 단일 변수 중

내가 변수가 말 :

double aPass; 

을 나는이 변수를 보호하려는, 그래서 난 뮤텍스 생성 :

pthread_mutex_t aPass_lock; 

지금 내가이 일을 생각할 수있는 두 가지 좋은 방법이 있습니다를 그러나 둘 다 성가신 단점이 있습니다. 첫 번째는 변수를 개최 스레드 안전 클래스를 만드는 것입니다 :

class aPass { 
    public: 
     aPass() { 
      pthread_mutex_init(&aPass_lock, NULL); 
      aPass_ = 0; 
     } 

     void get(double & setMe) { 
      pthread_mutex_lock(aPass_lock); 
      setMe = aPass_ 
      pthread_mutex_unlock(aPass_lock); 
     } 

     void set(const double setThis) { 
      pthread_mutex_lock(aPass_lock); 
      aPass_ = setThis; 
      pthread_mutex_unlock(aPass_lock); 
     } 
    private: 
     double aPass_; 
     pthread_mutex_t aPass_lock; 
}; 

지금이 YAY, 만지지 적 aPass 완전히 안전, 아무것도 잘못 될 수 유지됩니다! 그러나 모든 엉망진창을보고 그것에 액세스 할 때의 혼란을 상상해보십시오. 심한.

다른 방법은 패스를 사용하기 전에 뮤텍스를 액세스 할 수있게하고 뮤텍스를 잠그는 것입니다.

pthread_mutex_lock(aPass_lock); 
    do something with aPass 
pthread_mutex_unlock(aPass_lock); 

하지만 새로운 사람이 프로젝트에 온다면, 한 번만 잊어 버리면 어떻게 될까요? 나는 그들이 어렵다고 디버깅 스레드 문제를 좋아하지 않아.

QNX를 약간의 부스트 지원으로 사용해야하기 때문에 pthread를 사용하는 것이 좋습니다. 큰 클래스가 필요하지 않고 단일 변수를 잠 그려면 더 안전한 다음 뮤텍스 잠금을 만들어야합니다.

+0

이 변수는 전역 변수입니까? 내가 다른 많은 선택의 여지가 없다고 생각해 .. 만약 당신이 일반적인 스레드 안전 컨테이너 클래스를 만들고 싶지 않다면 - 이것은 두 번째 var에 이것을해야한다면 몇 가지 코드를 줄 것이다. –

+0

템플릿 기반 클래스의 의미는 무엇입니까? 그 소리가 꽤 좋아. –

+0

또한, 그것을 통해 UR 디자인을 복제 할 수 없는가? apass는 클래스이기 때문에 내가 원하는만큼의 객체를 가질 수 있습니다. –

답변

3

내 솔루션에 활력을 불어 넣으려면 다음과 같이하십시오.

template <typename ThreadSafeDataType> 
class ThreadSafeData{ 
    //.... 
private: 
    ThreadSafeDataType data; 
    mutex mut; 
}; 

class apass:public ThreadSafeData<int> 

또한 고유하게 만들려면 모든 운영자와 구성원을 정적으로 설정하는 것이 가장 좋습니다. 이것은 당신이 코드는 바로 생각입니다 아래 CRTP

template <typename ThreadSafeDataType,class DerivedDataClass> 
class ThreadSafeData{ 
//.... 
}; 
class apass:public ThreadSafeData<int,apass> 
+1

안녕하십니까. 귀하의 의사 소통에 txt-speak를 사용하지 마십시오. 여기에 필요가 없으며 일반적으로 눈살을 찌푸리게됩니다. – GManNickG

1

변수에 대한 액세스를 동기화하는 일반적인 래퍼 역할을하는 클래스를 만들 수 있습니다.

할당에 대한 연산자 오버로딩을 추가하면 완료됩니다.

+0

몇 가지 예제 코드? 또한 당신이 그 유형에 대한 각 함수의 오버로딩과 함께 하나의 클래스에서 사용하고자하는 각각의 변수 유형을 가지고 있다는 것을 의미합니까? 꽤 지저분 해 보인다. –

+0

모든 데이터 유형에서 사용할 수있는 템플릿 클래스를 만들 수 있습니다. – thedayofcondor

+0

@ Karthik T 코드를 참조하십시오 ... 내 C++은 약간 녹슬고 IDE가 없으면 머리 꼭대기에서 쓸 수 없습니다 ... 너무 오래되었습니다. – thedayofcondor

1

RAII idiom를 사용 고려 사용할 필요가 작동하려면, 시험 아니에요 :

template<typename T, typename U> 
struct APassHelper : boost::noncoypable 
{ 
    APassHelper(T&v) : v_(v) { 
    pthread_mutex_lock(mutex_); 
    } 
    ~APassHelper() { 
    pthread_mutex_unlock(mutex_); 
    } 
    UpdateAPass(T t){ 
    v_ = t; 
    } 
private: 
    T& v_; 
    U& mutex_; 
}; 

double aPass; 
int baPass_lock; 
APassHelper<aPass,aPass_lock) temp; 
temp.UpdateAPass(10); 
+0

이것은 여전히 ​​사용자가 도우미를 수동으로 사용하도록 요구합니다. OP는 피하려고합니다. –

2

당신은 쉽게 자신의 클래스를 만들 수있는 잠금이 뮤텍스를 사용하고, 파괴시 잠금을 해제합니다. 이런 식으로 어떤 일이 발생하더라도 mutex는 예외가 던져 지거나 경로가 취해 지더라도 반환 할 때 해제됩니다.

class MutexGuard 
{ 
    MutexType & m_Mutex; 
public: 

    inline MutexGuard(MutexType & mutex) 
     : m_Mutex(mutex) 
    { 
     m_Mutex.lock(); 
    }; 

    inline ~MutexGuard() 
    { 
     m_Mutex.unlock(); 
    }; 
} 


class TestClass 
{ 
    MutexType m_Mutex; 
    double m_SharedVar; 

    public: 
     TestClass() 
      : m_SharedVar(4.0) 
     { } 

     static void Function1() 
     { 
      MutexGuard scopedLock(m_Mutex); //lock the mutex 
      m_SharedVar+= 2345; 
      //mutex automatically unlocked 
     } 
     static void Function2() 
     { 
      MutexGuard scopedLock(m_Mutex); //lock the mutex 
      m_SharedVar*= 234; 
      throw std::runtime_error("Mutex automatically unlocked"); 
     } 

} 

변수 m_SharedVar는 Function1()Function2() 사이에 상호 배제를 보장하고, 항상 반환에 잠금이 해제됩니다.

부스트에는 다음을 수행하는 유형이 빌드되어 있습니다. boost :: scoped_locked, boost :: lock_guard.

+1

멋진 답변이지만 불행히도 저는 제 질문에서 사용하지 않을 것입니다. 그렇지 않으면 나는 모든 범위의 뮤텍스 잠금이 될 것이다. –

+3

그는 자신의 범위가 지정된 잠금을 만드는 방법을 보여 줬습니다 –

1

대신 GET/세트의 연산자를 사용하여 aPass 클래스를 수정할 수 있습니다

class aPass { 
public: 
    aPass() { 
     pthread_mutex_init(&aPass_lock, NULL); 
     aPass_ = 0; 
    } 

    operator double() const { 
     double setMe; 
     pthread_mutex_lock(aPass_lock); 
     setMe = aPass_; 
     pthread_mutex_unlock(aPass_lock); 
     return setMe; 
    } 

    aPass& operator = (double setThis) { 
     pthread_mutex_lock(aPass_lock); 
     aPass_ = setThis; 
     pthread_mutex_unlock(aPass_lock); 
     return *this; 
    } 
private: 
    double aPass_; 
    pthread_mutex_t aPass_lock; 
}; 

사용법 :

aPass a; 
a = 0.5; 
double b = a; 

이것은 물론 다른 유형을 지원하는 템플릿 수 있습니다. 그러나 뮤텍스는이 경우 잔인합니다. 일반적으로 메모리 장벽은 작은 데이터 유형의로드 및 저장을 보호 할 때 충분합니다. 가능한 경우 C++ 11 std::atomic<double>을 사용해야합니다.

5
std::atomic<double> aPass; 

(C++ 11이있는 경우)

+0

불행히도 아니오, 저는 C++ 11이 없습니다. –