9

スレッドセーフの概念を理解しています。単一の変数を保護しようとするときにスレッドセーフを簡素化するためのアドバイスを探しています。

変数があるとしましょう:

double aPass;

この変数を保護したいので、ミューテックスを作成します。

pthread_mutex_t aPass_lock;

今、私がこれを行うことを考えることができる2つの良い方法がありますが、どちらも厄介な欠点があります。1つ目は、変数を保持するスレッドセーフクラスを作成することです。

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;
};

今、これはaPass完全に安全に保たれます、何も間違えられることはなく、それに触れることはありません、イェーイ!しかし、そのすべての混乱を見て、それにアクセスするときの混乱を想像してください。キモい。

もう1つの方法は、両方にアクセスできるようにすることと、aPassを使用する前にミューテックスをロックすることを確認することです。

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

しかし、新しい誰かがプロジェクトに参加した場合、一度ロックするのを忘れた場合はどうなりますか。難しいスレッドの問題をデバッグするのは好きではありません。

(ブーストサポートがほとんどないQNXを使用する必要があるため、pthreadを使用する)大きなクラスを必要とせずに単一の変数をロックするための良い方法はありますか?それは、それに合わせてミューテックスロックを作成するよりも安全ですか?

4

6 に答える 6

24
std::atomic<double> aPass;

C++11をお持ちの場合。

于 2012-11-09T12:42:54.957 に答える
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>
于 2012-11-09T01:29:49.527 に答える
2

構築時にミューテックスをロックし、破壊時にロックを解除する独自のクラスを簡単に作成できます。このように、何が起こっても、例外がスローされたり、パスが取られたりしても、ミューテックスはリターン時に解放されます。

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には、これを実現するためのタイプが組み込まれています:boost :: scoped_locked、boost::lock_guard。

于 2012-11-09T01:32:05.227 に答える
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);
于 2012-11-09T01:31:04.137 に答える
1

変数へのアクセスを同期する変数の汎用ラッパーとして機能するクラスを作成できます。

割り当てに演算子のオーバーロードを追加すれば完了です。

于 2012-11-09T01:25:15.720 に答える
1

get / setの代わりに演算子を使用して、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>

于 2012-11-09T02:39:50.107 に答える