Проблемы с использованием 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);
}

при компиляции у меня такая проблема на вызов EnterCriticalSection(&cs) и LeaveCriticalSection(&cs):

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

Я не знаю, что это неправильно. Может быть, вы видите. Просто потому, что я всегда использовал его таким образом, и все было в порядке. windows.h включен

6 ответов


просто объявить cs as:

mutable CRITICAL_SECTION cs;

или удалите предложение const на size()

ввод критического раздела изменяет CRITICAL_SECTION, и уход изменяет его снова. Поскольку вход и выход из критического раздела не делает size() вызов метода логически не-const, Я бы сказал, Оставьте его объявленным const, и сделать cs mutable. Это тип ситуации mutable был представлен для.

также-взгляните на Мартин-Йорки Джо Mucchielloпредложения-Используйте RAII, когда это возможно, чтобы иметь дело с любыми ресурсами, которые необходимо очистить. Это работает так же хорошо для критических разделов, как и для указателей и дескрипторов файлов.


также приведенный выше код не является исключением.
Нет никакой гарантии, что push_back() pop_back() не бросят. Если они это сделают, они оставят ваш критический раздел навсегда заблокирован. Вы должны создать класс locker, который вызывает 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 () позаботится об этом.


Я предпочитаю использовать отдельный объект приобретения над вашим кодом. Ваш код, если хрупкий, когда возникает исключение между вызовами 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);
}

EnterCriticalSection не нужно const


Я вижу, что вы объявили пустой конструктор копирования:

SharedVector(const SharedVector& rhs) {}

как я уверен, вы знаете, эта функция ничего не делает, и это также оставляет cs неинициализированное. Потому что ваш класс содержит экземпляр CRITICAL_SECTION, вы должны быть уверены, чтобы запретить конструктор копирования и оператор присваивания, если вы собираетесь их полностью реализовать. Вы можете сделать это, поместив следующие объявления в класс:

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

этот предотвращает компилятор от автоматической генерации неправильных версий этих методов, а также предотвращает их вызов в другом коде, который вы пишете (потому что это только объявления, но не определения с {} код блоков).

также, как Арнаут упоминалось, конструктор, который принимает


Так, это что-то не так с правами доступа. Я сделал метод size () non-const, и теперь все в порядке.