【问题标题】:Problems using EnterCriticalSection使用 EnterCriticalSection 的问题
【发布时间】:2010-09-27 22:44:24
【问题描述】:

我需要处理来自多个线程的数组,因此我使用 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(&amp;cs)LeaveCriticalSection(&amp;cs) 时遇到这样的问题:

'EnterCriticalSection' : 无法将参数 1 从 'const CRITICAL_SECTION *' 到 'LPCRITICAL_SECTION'

我不知道出了什么问题。也许你可以看到。只是因为我总是这样使用它,而且没关系。包含windows.h

【问题讨论】:

  • 不要写模板,而是写模板

标签: c++ winapi critical-section


【解决方案1】:

只需将cs 声明为:

mutable CRITICAL_SECTION cs;

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

进入临界区会修改CRITICAL_SECTION,离开会再次修改它。由于进入和离开临界区不会使size() 方法在逻辑上调用非const,我会说让它声明const,并使其cs mutable。这就是mutable 被引入的情况类型。

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

【讨论】:

    【解决方案2】:

    上面的代码也不是异常安全的。
    不能保证 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() 能解决这个问题。

    【讨论】:

      【解决方案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);
      }
      

      【讨论】:

        【解决方案4】:

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

        另外,您确定要将关键部分传递给您的 ctor,然后让 ctor 执行 InitializeCriticalSection 调用吗?如果你想分享你的关键部分,我想你应该先初始化它,然后再分发出去。

        【讨论】:

          【解决方案5】:

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

          SharedVector(const SharedVector& rhs) {}
          

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

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

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

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

          【讨论】:

            【解决方案6】:

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

            【讨论】:

            • 选择的答案(使用 mutable)肯定更好。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多