我需要处理来自多个线程的数组,因此我使用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);
}
编译时我遇到调用EnterCriticalSection(&cs)
和LeaveCriticalSection(&cs)
的问题:
'EnterCriticalSection' : cannot convert parameter 1 from 'const CRITICAL_SECTION *' to 'LPCRITICAL_SECTION'
我不知道出了什么问题。可能你可以看到。只是因为我总是以这种方式使用它而且没关系。包含windows.h
答案 0 :(得分:20)
只需将cs
声明为:
mutable CRITICAL_SECTION cs;
或删除size()
输入关键部分会修改CRITICAL_SECTION
,然后再次修改它。由于进入和离开关键部分不会使size()
方法调用逻辑上不是const
,我会说它保留为const
,并使cs
{{ 1}}。这是mutable
引入的情况类型。
另外 - 看看Martin York和Joe Mucchiello的建议 - 尽可能使用RAII来处理需要清理的任何类型的资源。这对于关键部分和指针和文件句柄一样适用。
答案 1 :(得分:6)
上面的代码也不是Exception安全的 无法保证push_back()pop_back()不会抛出。如果他们这样做,他们将永久锁定您的关键部分。你应该创建一个在构造上调用EnterCriticalSection()的locker类,在破坏时调用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()能够解决这个问题。
答案 2 :(得分:3)
我更喜欢在代码上使用单独的Acquisition对象。在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);
}
答案 3 :(得分:1)
EnterCriticalSection
不接受 const 参数。那是编译错误,BTW,而不是链接错误...
此外,您确定要将关键部分传入您的ctor,然后让ctor执行InitializeCriticalSection
来电吗?如果你想分享你的关键部分,我想你先将它初始化,然后再把它分发出来。
答案 4 :(得分:1)
我看到你宣布了一个空的拷贝构造函数:
SharedVector(const SharedVector& rhs) {}
我确信你知道,这个函数什么都不做,而且cs
也没有初始化。因为您的类包含CRITICAL_SECTION
的实例,所以您必须确保禁止复制构造函数和赋值运算符调用,除非您要完全实现它们。您可以通过在类的private
部分中放置以下声明来完成此操作:
SharedVector(const SharedVector &);
SharedVector &operator=(const SharedVector &);
这可以防止编译器自动生成这些方法的错误版本,并且还阻止您在其他编写的代码中调用它们(因为这些只是声明,而不是{}
代码块的定义)。 / p>
此外,正如Arnout所提到的,采用CRITICAL_SECTION&
参数的构造函数似乎是错误的。您的实现所做的是将传入的关键部分复制到cs
(这与CRITICAL_SECTION
无关),然后调用InitializeCriticalSection(&cs)
覆盖您刚刚执行的副本并创建一个 new 关键部分。对于通过一个关键部分的来电者来说,这似乎是通过有效地忽略传入的内容来做错事。
答案 5 :(得分:0)
所以,访问权限有问题。 我使size()方法非const,现在没问题。