使用 EnterCriticalSection 时出现的问题

发布于 2024-07-09 22:17:17 字数 2039 浏览 8 评论 0原文

我需要使用多个线程中的数组,因此我使用 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

I need to work with array from several threads, so I use CRITICAL SECTION to give it an exclusive access to the data.
Here is my template:

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

While compiling I have such a problem for calling EnterCriticalSection(&cs) and LeaveCriticalSection(&cs):

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

I do not know what is wrong. May be you can see. Just because I always used it this way and it was alright. windows.h is included

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

骄傲 2024-07-16 22:17:17

只需将 cs 声明为:

mutable CRITICAL_SECTION cs;

或者删除 size() 上的 const 子句。

进入临界区会修改 CRITICAL_SECTION,离开则会再次修改它。 由于进入和离开关键部分不会使 size() 方法调用在逻辑上成为非 const,因此我建议将其声明为 const >,并使 cs 可变mutable 正是针对这种情况而引入的。

另外 - 看看 Martin YorkJoe Mucchiello 的建议 - 尽可能使用 RAII 来处理需要清理的任何类型的资源。 这对于关键部分和指针和文件句柄一样有效。

Just declare cs as:

mutable CRITICAL_SECTION cs;

or else remove the const clause on size()

Entering a critical section modifies the CRITICAL_SECTION, and leaving modifies it again. Since entering and leaving a critical section doesn't make the size() method call logically non-const, I'd say leave it declared const, and make cs mutable. This is the type of situation mutable was introduced for.

Also - take a look at Martin York's and Joe Mucchiello's suggestions - use RAII whenever possible to deal with any kind of resources that need to be cleaned up. This works just as well for critical sections as it does for pointers and file handles.

稀香 2024-07-16 22:17:17

另外上面的代码不是异常安全的。
不保证push_back() pop_back()不会抛出异常。 如果他们这样做,他们将使您的关键部分永久锁定。 您应该创建一个储物柜类,在构造时调用 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() 能够解决这个问题。

Also the code above is not Exception safe.
There is no guarantee that push_back() pop_back() will not throw. If they do they will leave your critical section permanently locked. You should create a locker class that calls EnterCriticalSection() on construction and LeaveCriticalSection() on destruction.

Also this makes your methods a lot easier to read. (see below)

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

Another thing you should worry about. Is making sure that when you destroy the object you have ownership and that nobody else tries to take ownership during destruction. Hopefully your DestoryCriticalSection() takes care of this.

许仙没带伞 2024-07-16 22:17:17

我更喜欢使用单独的 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);
}

I prefer using a separate Acquisition object over your code. Your code if fragile when an exception occurs between the Enter and Leave calls:

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

Then in your class methods you would code it as:

template <typename T>
void SharedVector::PushBack(const T& value) {
   CS_Acquire acquire(&cs);
   vect.push_back(value);
}
那一片橙海, 2024-07-16 22:17:17

EnterCriticalSection 不接受 const 参数。 顺便说一句,这是一个编译错误,而不是链接错误...

另外,您确定要将关键部分传递到您的构造函数中,然后让该构造函数执行 InitializeCriticalSection 调用吗? 如果你想共享你的关键部分,我想你应该先初始化它,然后再分发它。

EnterCriticalSection doesn't take a const argument. That's a compilation error, BTW, not a linking error...

Also, are you sure you want to pass in a critical section into your ctor, and then have the ctor perform the InitializeCriticalSection call? If you want to share your critical section, I suppose you'd initialize it first, and then hand it out.

伴我老 2024-07-16 22:17:17

我看到您声明了一个空的复制构造函数:

SharedVector(const SharedVector& rhs) {}

我确信您知道,这个函数什么也不做,而且它还使 cs 未初始化。 由于您的类包含 CRITICAL_SECTION 的实例,因此您必须确保禁止复制构造函数和赋值运算符调用,除非您要完全实现它们。 您可以通过在类的 private 部分中放置以下声明来实现此目的:

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

这可以防止编译器自动生成这些方法的错误版本,也可以防止您在编写的其他代码中调用它们(因为这些只是声明,而不是带有 {} 代码块的定义)。

另外,正如 Arnout 提到的,采用 CRITICAL_SECTION& 的构造函数论证似乎是错误的。 您的实现所做的是将传入的关键部分复制到 cs (这对于 CRITICAL_SECTION 来说不是有效的操作),然后调用 InitializeCriticalSection(& ;cs) 它会覆盖您刚刚所做的副本并创建一个新的关键部分。 对于传入关键部分的调用者来说,这似乎通过有效地忽略传入的内容而做了错误的事情。

I see you have declared an empty copy constructor:

SharedVector(const SharedVector& rhs) {}

As I'm sure you are aware, this function does nothing, and it also leaves cs uninitialised. Because your class contains an instance of a CRITICAL_SECTION, you must be sure to disallow copy constructor and assignment operator calls unless you are going to implement them completely. You can do this by placing the following declarations in the private section of your class:

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

This prevents the compiler from auto-generating incorrect versions of these methods, and also prevents you from calling them in other code you write (because these are only declarations, but not definitions with {} code blocks).

Also, as Arnout mentioned, the constructor that takes a CRITICAL_SECTION& argument seems wrong. What your implementation does is copy the passed-in critical section to cs (which is not a valid thing to do with a CRITICAL_SECTION), then calls InitializeCriticalSection(&cs) which overwrites the copy you just did and creates a new critical section. To the caller who passed in a critical section, this seems to do the wrong thing by effectively ignoring whatever was passed in.

別甾虛僞 2024-07-16 22:17:17

所以,访问权限有问题。
我将 size() 方法设置为非常量,现在可以了。

so, it`s something wrong with access rights.
I made size() method non-const and now it is ok.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文