2008-12-21 5 views
5

je dois travailler avec tableau à partir de plusieurs threads, donc j'utiliser la section CRITIQUE pour lui donner un accès exclusif aux données.
Voici mon modèle:
Problèmes d'utilisation EnterCriticalSection

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

Lors de la compilation J'ai un problème pour appeler EnterCriticalSection(&cs) et LeaveCriticalSection(&cs):

 
'EnterCriticalSection' : cannot convert parameter 1 from 
'const CRITICAL_SECTION *' to 'LPCRITICAL_SECTION' 

Je ne sais pas ce qui est faux. Peut être vous pouvez voir. Juste parce que je l'ai toujours utilisé de cette façon et tout allait bien. windows.h est inclus

+0

Ne pas écrire modèle , mais modèle pyon

Répondre

20

Tout comme cs déclare:

mutable CRITICAL_SECTION cs; 

ou bien supprimer la clause const sur size()

Saisie d'une section critique modifie la CRITICAL_SECTION, et en laissant à nouveau le modifie. Depuis son entrée et en laissant une section critique ne rend pas la non logiquement appel de méthode size()const, je dirais que laisser déclaré const et faire csmutable. C'est le type de situation mutable a été introduit pour. En outre - jetez un oeil à Martin York et Joe Mucchiello suggestions - utiliser RAII chaque fois que possible pour faire face à tout type de ressources qui ont besoin d'être nettoyé. Cela fonctionne aussi bien pour les sections critiques que pour les pointeurs et les handles de fichiers.

1

EnterCriticalSection ne prend pas un const argument. C'est une erreur de compilation, d'ailleurs, pas une erreur de liaison ...

Aussi, êtes-vous sûr de vouloir passer dans une section critique dans votre cteur, et alors le cteur effectuer l'appel InitializeCriticalSection? Si vous voulez partager votre section critique, je suppose que vous l'initialisez d'abord, puis que vous la distribuez.

0

donc, il s `quelque chose de mal avec les droits d'accès. J'ai fait la méthode size() non-const et maintenant c'est ok.

+0

La réponse sélectionnée (utiliser mutable) est définitivement meilleure. –

1

Je vois que tu as déclaré un constructeur de copie vide:

SharedVector(const SharedVector& rhs) {} 

Comme je suis sûr que vous savez, cette fonction ne fait rien, et il laisse aussi cs uninitialised. Comme votre classe contient une instance de CRITICAL_SECTION, vous devez vous assurer de ne pas autoriser le constructeur de copie et les appels d'opérateur d'affectation, à moins que vous n'ayez à les implémenter complètement. Vous pouvez le faire en plaçant les déclarations suivantes dans la section private de votre classe:

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

Cela empêche le compilateur de versions incorrectes de ces méthodes de génération automatique, et vous empêche de les appeler dans un autre code que vous écrivez (parce que ce ne sont que des déclarations, mais pas des définitions avec {} blocs de code).

De même, comme Arnout mentionné, le constructeur qui prend un argument CRITICAL_SECTION& semble faux.Ce que votre mise en œuvre ne copie est la section critique refacturés pour cs (ce qui est une chose valable de le faire avec un CRITICAL_SECTION), puis appelle InitializeCriticalSection(&cs) qui remplace la copie que vous venez de faire et crée une nouvelle section critique. Pour l'appelant qui est passé dans une section critique, cela semble faire la mauvaise chose en ignorant effectivement tout ce qui a été passé.

6

Aussi le code ci-dessus n'est pas Exception safe.
Il n'y a aucune garantie que push_back() pop_back() ne sera pas lancé. S'ils le font, ils laisseront votre section critique définitivement verrouillée. Vous devez créer une classe locker qui appelle EnterCriticalSection() sur la construction et LeaveCriticalSection() sur la destruction.

Cela rend également vos méthodes beaucoup plus faciles à lire. (Voir ci-dessous)

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

Une autre chose que vous devriez vous inquiéter. S'assure que lorsque vous détruisez l'objet vous avez la propriété et que personne d'autre n'essaie d'en prendre possession pendant la destruction. Heureusement, votre DestoryCriticalSection() prend soin de cela.

2

Je préfère utiliser un objet d'acquisition distinct sur votre code. Votre code si fragile lorsqu'une exception se produit entre les entrer et sortir des appels:

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

Ensuite, dans vos méthodes de classe vous serait-il code comme:

template <typename T> 
void SharedVector::PushBack(const T& value) { 
    CS_Acquire acquire(&cs); 
    vect.push_back(value); 
}