7

複数のスレッドから配列を操作する必要があるため、CRITICAL SECTION を使用してデータへの排他的アクセスを許可します。
ここに私のテンプレートがあります:

#include "stdafx.h"
#ifndef SHAREDVECTOR_H
#define SHAREDVECTOR_H

#include <vector>
#include <windows.h>

template<class T>
class SharedVector {
    std::vector<T> vect;
    CRITICAL_SECTION cs;
    SharedVector(const SharedVector<T>& rhs) {}
public:
    SharedVector();
    explicit SharedVector(const CRITICAL_SECTION& CS);
    void PushBack(const T& value);
    void PopBack();
    unsigned int size() const;
    T& operator[](int index);
    virtual ~SharedVector();
};

template<class T>
SharedVector<T>::SharedVector() {
    InitializeCriticalSection(&cs);
}

template<class T>
SharedVector<T>::SharedVector(const CRITICAL_SECTION& r): cs(r) {
    InitializeCriticalSection(&cs);
}

template<class T>
void SharedVector<T>::PushBack(const T& value) {
    EnterCriticalSection(&cs);
    vect.push_back(value);
    LeaveCriticalSection(&cs);
}

template<class T>
void SharedVector<T>::PopBack() {
    EnterCriticalSection(&cs);
    vect.pop_back();
    LeaveCriticalSection(&cs);
}

template<class T>
unsigned int SharedVector<T>::size() const {
    EnterCriticalSection(&cs);
    unsigned int result = vect.size();
    LeaveCriticalSection(&cs);
    return result;
}

template<class T>
T& SharedVector<T>::operator[](int index) {
    EnterCriticalSection(&cs);
    T result = vect[index];
    LeaveCriticalSection(&cs);
    return result;
}

template<class T>
SharedVector<T>::~SharedVector() {
    DeleteCriticalSection(&cs);
}

コンパイル中に、 and の呼び出しに次のような問題がEnterCriticalSection(&cs)ありLeaveCriticalSection(&cs)ます。

'EnterCriticalSection': パラメータ 1 を変換できません
「const CRITICAL_SECTION *」から「LPCRITICAL_SECTION」

何が悪いのかわかりません。見えるかも。いつもこのように使っていて大丈夫だったからです。windows.h含まれています

4

6 に答える 6

20

次のように宣言するcsだけです:

mutable CRITICAL_SECTION cs;

または、 const 句を削除しますsize()

クリティカル セクションに入ると がCRITICAL_SECTION変更され、退出すると再び変更されます。クリティカル セクションに出入りしても、size()メソッド呼び出しは論理的に non-constにはならないので、宣言されたままにしconst、 make としcs mutableます。mutableこれは、導入された状況のタイプです。

また、Martin YorkJoe Mucchielloの提案を見てください。クリーンアップが必要なあらゆる種類のリソースに対処するために、可能な限り RAII を使用してください。これは、ポインターやファイル ハンドルの場合と同様に、クリティカル セクションでも同様に機能します。

于 2008-12-21T20:45:39.620 に答える
7

また、上記のコードは例外セーフではありません。
push_back() pop_back() がスローしないという保証はありません。そうした場合、クリティカル セクションは永久にロックされたままになります。構築時に EnterCriticalSection() を呼び出し、破棄時に LeaveCriticalSection() を呼び出すロッカー クラスを作成する必要があります。

また、これによりメソッドが読みやすくなります。(下記参照)

class CriticalSectionLock
{
    public:
        CriticalSectionLock(CRITICAL_SECTION& cs)
            : criticalSection(cs)
        {
            EnterCriticalSection(&criticalSection);
        }
        ~CriticalSectionLock()
        {
            LeaveCriticalSection(&criticalSection);
        }
    private:
        CRITICAL_SECTION&  criticalSection;
};


// Usage
template
unsigned int SharedVector::size() const
{
    CriticalSectionLock  lock(cs);
    return vect.size();
}

あなたが心配すべきもう一つのこと。オブジェクトを破棄するときに所有権があり、破棄中に他の誰も所有権を取得しようとしないことを確認しています。うまくいけば、あなたの DestoryCriticalSection() がこれを処理します。

于 2008-12-21T22:27:13.457 に答える
3

コードよりも別の取得オブジェクトを使用することをお勧めします。Enter 呼び出しと Leave 呼び出しの間で例外が発生したときにコードが壊れやすい場合:

class CS_Acquire {
    CRITICAL_SECTION &cs;
public:
    CS_Acquire(CRITICAL_SECTION& _cs) : cs(_cs) { EnterCriticalSection(cs); }
    ~CS_Acquire() { LeaveCriticalSection(cs); }
};

次に、クラスメソッドで次のようにコーディングします。

template <typename T>
void SharedVector::PushBack(const T& value) {
   CS_Acquire acquire(&cs);
   vect.push_back(value);
}
于 2008-12-21T22:40:37.187 に答える
1

空のコピー コンストラクターを宣言したようです。

SharedVector(const SharedVector& rhs) {}

ご承知のとおり、この関数は何もせず、初期化もされませんcs。クラスには のインスタンスが含まれているため、CRITICAL_SECTION完全に実装する場合を除き、コピー コンストラクターと代入演算子の呼び出しを禁止する必要があります。privateこれを行うには、クラスのセクションに次の宣言を配置します。

SharedVector(const SharedVector &);
SharedVector &operator=(const SharedVector &);

これにより、コンパイラがこれらのメソッドの誤ったバージョンを自動生成するのを防ぎ、ユーザーが記述した他のコードでそれらを呼び出すこともできなくなります (これらは単なる宣言であり、{}コード ブロックでの定義ではないため)。

また、ArnoutCRITICAL_SECTION&が述べたように、引数を取るコンストラクターは間違っているようです。あなたの実装では、渡されたクリティカル セクションを にコピーしcs(これは a で行うのは有効ではありませんCRITICAL_SECTION)、次に、InitializeCriticalSection(&cs)今行ったコピーを上書きして新しいクリティカル セクションを作成する を呼び出します。クリティカル セクションを渡した呼び出し元には、渡されたものを事実上無視することで、間違ったことをしているように見えます。

于 2008-12-21T21:24:34.300 に答える
1

EnterCriticalSectionconst引数を取りません。それはリンクエラーではなく、コンパイルエラーです...

また、クリティカル セクションを ctor に渡し、ctor にInitializeCriticalSection呼び出しを実行させますか? クリティカル セクションを共有する場合は、最初に初期化してから配布すると思います。

于 2008-12-21T20:43:41.870 に答える
0

つまり、アクセス権に問題があります。size() メソッドを非定数にしましたが、今は問題ありません。

于 2008-12-21T20:49:09.847 に答える