2008-12-21 8 views
5

Necesito trabajar con una matriz de varios subprocesos, por lo que utilizo CRITICAL SECTION para otorgarle un acceso exclusivo a los datos.
Aquí está mi plantilla:
Problemas al utilizar 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); 
} 

Durante la compilación que tienen un problema para llamar EnterCriticalSection(&cs) y LeaveCriticalSection(&cs):

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

No sé lo que está mal. Puede ser que puedas ver. Solo porque siempre lo usé de esta manera y estuvo bien. windows.h está incluido

+0

No escriba plantilla , pero la plantilla pyon

Respuesta

20

Sólo declaran como cs:

mutable CRITICAL_SECTION cs; 

o bien eliminar la cláusula const en size()

Introducción de una sección crítica modifica la CRITICAL_SECTION y dejando lo modifica de nuevo. Como entrar y salir de una sección crítica no hace que el método size() llame lógicamente a no const, yo diría que lo deje declarado const, y haga csmutable. Este es el tipo de situación para la que se introdujo mutable.

Además, eche un vistazo a las sugerencias de Martin York y Joe Mucchiello: utilice RAII siempre que sea posible para tratar con cualquier clase de recursos que deban limpiarse. Esto funciona igual de bien para secciones críticas que para punteros y manejadores de archivos.

1

EnterCriticalSection no toma un argumento const. Eso es un error de compilación, por cierto, no es un error de vinculación ...

Además, ¿está seguro de que desea pasar una sección crítica a su ctor y hacer que el ctor realice la llamada InitializeCriticalSection? Si quieres compartir tu sección crítica, supongo que debes inicializarla primero y luego repartirla.

0

por lo tanto, es algo malo con los derechos de acceso. He hecho que el método size() no const y ahora está bien.

+0

La respuesta seleccionada (use mutable) es definitivamente mejor. –

1

veo que tiene declarada una copia constructor vacío:

SharedVector(const SharedVector& rhs) {} 

Como estoy seguro de que son conscientes, esta función no hace nada, y también deja cs sin inicializar. Debido a que su clase contiene una instancia de CRITICAL_SECTION, debe asegurarse de no permitir las llamadas del constructor de copias y del operador de asignación a menos que vaya a implementarlas por completo. Usted puede hacer esto mediante la colocación de las siguientes declaraciones en la sección private de su clase:

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

Esto evita que el compilador de versiones incorrectas generación automática de estos métodos, y también le impide llamarlos en otro código que escriba (porque estas son solo declaraciones, pero no definiciones con los bloques de código {}).

También, como Arnout mencionado, el constructor que toma un argumento CRITICAL_SECTION& parece incorrecto.Lo que hace su implementación es copiar la sección crítica pasada al cs (que no es válida con un CRITICAL_SECTION), luego llama al InitializeCriticalSection(&cs) que sobrescribe la copia que acaba de hacer y crea una nueva sección crítica . Para la persona que llama que pasó en una sección crítica, esto parece hacer lo incorrecto al ignorar efectivamente lo que pasó.

6

Además, el código anterior no es Excepción segura.
No hay garantía de que push_back() pop_back() no arrojará. Si lo hacen, dejarán tu sección crítica permanentemente bloqueada. Debería crear una clase de bloque que llame a EnterCriticalSection() en la construcción y LeaveCriticalSection() en la destrucción.

También esto hace que sus métodos sean mucho más fáciles de leer. (ver a continuación)

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

Otra cosa que debe preocuparse. Es asegurarse de que cuando destruya el objeto que tiene la propiedad y que nadie más intente tomar la propiedad durante la destrucción. Con suerte, su DestoryCriticalSection() se ocupa de esto.

2

Prefiero usar un objeto de Adquisición separado sobre su código. Su código si frágil cuando se produce una excepción entre las llamadas entran y salen de:

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

Luego, en sus métodos de la clase que pudiera codificar como:

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