2008-12-21 17 views
5

Muszę pracować z tablicą z kilku wątków, więc używam SEKCJI KRYTYCZNEJ, aby zapewnić jej wyłączny dostęp do danych.
Oto mój szablon:
Problemy z korzystaniem z 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); 
} 

Podczas kompilacji mam taki problem za nazwanie EnterCriticalSection(&cs) i LeaveCriticalSection(&cs):

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

Nie wiem co jest nie tak. Może być widać. Tylko dlatego, że zawsze używałem tego w ten sposób i było w porządku. windows.h jest dołączone

+0

Nie pisz szablon , ale szablon pyon

Odpowiedz

20

Wystarczy zadeklarować cs jak:

mutable CRITICAL_SECTION cs; 

albo usunąć const klauzuli size()

Wprowadzanie sekcji krytycznej modyfikuje CRITICAL_SECTION, pozostawiając modyfikuje go ponownie. Ponieważ wejście i wyjście z sekcji krytycznej nie sprawia, że ​​wywołanie metody size() jest logicznie nie-const, powiedziałbym, że zadeklarowałem const, i zrobię cs. Jest to rodzaj sytuacji, dla której wprowadzono mutable.

Również - spójrz na sugestie Martin York i Joe Mucchiello - korzystaj z RAI, gdy tylko jest to możliwe, aby poradzić sobie z wszelkimi zasobami, które wymagają oczyszczenia. Działa to równie dobrze w przypadku sekcji krytycznych, jak w przypadku wskaźników i uchwytów plików.

1

EnterCriticalSection nie przyjmuje argumentu const. To jest błąd kompilacji, BTW, a nie błąd łączenia ...

Czy na pewno chcesz przekazać krytyczną sekcję do swojego ctor, a następnie zlecić citorowi wykonanie połączenia InitializeCriticalSection? Jeśli chcesz udostępnić swoją sekcję krytyczną, przypuszczam, że najpierw ją zainicjowałeś, a potem rozdałeś.

0

, więc coś jest nie tak z prawami dostępu. Stworzyłem metodę size() nie-const i teraz jest w porządku.

+0

Wybrana odpowiedź (użyj mutable) jest zdecydowanie lepsza. –

1

Widzę, że ogłoszony pusta kopia konstruktora:

SharedVector(const SharedVector& rhs) {} 

Jestem pewien, że są świadomi, funkcja ta nic nie robi, a także pozostawia cs zainicjalizowana. Ponieważ twoja klasa zawiera instancję CRITICAL_SECTION, musisz odrzucić konstruktor kopiowania i wywołania operatora przypisania, chyba że zamierzasz je całkowicie wdrożyć. Można to zrobić poprzez umieszczenie następujące deklaracje w sekcji private swojej klasie:

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

Zapobiega to kompilator z auto-generowanie błędnych wersji tych metod, a także uniemożliwia nazywając je w inny kod piszesz (ponieważ są to tylko deklaracje, ale nie definicje z blokami kodu {}).

Ponadto, jak wspomniano Arnout, konstruktor, który przyjmuje argument CRITICAL_SECTION&, wydaje się być nieprawidłowy.Twoja implementacja polega na skopiowaniu przekazanej krytycznej sekcji do cs (co nie jest poprawne z CRITICAL_SECTION), a następnie wywołuje InitializeCriticalSection(&cs), co powoduje nadpisanie właśnie wykonanej kopii i tworzy nową krytyczną sekcję new. Dla osoby dzwoniącej, która przeszła w krytycznej sekcji, wydaje się, że robi to złą rzecz, skutecznie ignorując to, co zostało przekazane.

6

Również powyższy kod nie jest bezpieczny pod względem wyjątku.
Nie ma gwarancji, że funkcja push_back() pop_back() nie zostanie wygenerowana. Jeśli to zrobią, pozostaną na stałe w sekcji krytycznej. Powinieneś utworzyć klasę szafki, która wywoła metodę EnterCriticalSection() przy konstrukcji i metodę LeaveCriticalSection() podczas niszczenia.

Również to sprawia, że ​​twoje metody są dużo łatwiejsze do odczytania. (zobacz poniżej)

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

Kolejna rzecz, o którą powinieneś się martwić. Upewnia się, że po zniszczeniu obiektu masz własność i że nikt inny nie próbuje przejąć własności podczas niszczenia. Mam nadzieję, że zajmie się tym DestoryCriticalSection().

2

Preferuję używanie oddzielnego obiektu Acquisition przez twój kod. Kod jeśli kruche, gdy wystąpi wyjątek pomiędzy wejście i wyjście połączeń:

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

Następnie w metodach klasy byś zakodować go jako:

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