如何正确离开关键部分?

时间:2015-05-01 10:05:15

标签: c++ windows exception exception-handling synchronization

我有以下C ++代码,我使用Critical Section object

EnterCriticalSection(&cs);

// code that may throw an exception

LeaveCriticalSection(&cs);

即使抛出异常,如何确保调用LeaveCriticalSection函数?

5 个答案:

答案 0 :(得分:9)

只需使用析构函数编写一个警卫进行清理:

struct Guard {
  CriticalSection& cs;
  Guard(CriticalSection& cs)
  : cs(cs)
  {
    EnterCriticalSection(cs);
  }
  ~Guard() {
    LeaveCriticalSection(cs);
  }
  Guard(const Guard&) = delete;  
  Guard& operator = (const Guard&) = delete;
};

用法:

void f() {
   Guard guard(cs);
   ...
}

答案 1 :(得分:8)

使用RAII(资源获取是初始化)习语:

struct GuardCS {
    GuardCS(CRITICAL_SECTION& p_cs) : cs(p_cs){
        EnterCriticalSection(&cs);
    }
    ~GuardCS() {
        LeaveCriticalSection(&cs);
    }
private:
    // Protect against copying, remove: =delete on pre c++11 compilers
    GuardCS(GuardCS const &) = delete;
    GuardCS& operator =(GuardCS const &) = delete;
    CRITICAL_SECTION& cs;
};

如果您正在使用MFC,那么有些类可以抽象出这些内容:is Ccriticalsection usable in production?

答案 2 :(得分:4)

  

“即使抛出异常,如何确保调用LeaveCriticalSection函数?”

您可以编写一个这样的小助手类:

 class CsLocker {
 public:
     CsLocker(CriticalSection& cs)
     : cs_(cs) {
         EnterCriticalSection(&cs_);
     }
     ~CsLocker() {
          LeaveCriticalSection(&cs);
     }
     CsLocker(const CsLocker&) = delete;
     CsLocker& operator=(const CsLocker&) = delete;
 private:
     CriticalSection& cs_;
 };

这将保证关键部分在任何时候(以及为什么有)范围被解锁时都会被解锁。

答案 3 :(得分:4)

我建议你不要使用WinAPI关键部分。您可以使用std::mutex获得相同的结果。使用它时,您还可以使用RAII idiom包装器自动解锁互斥锁(std::lock_guard)。

更新:关键部分和互斥锁之间的一个区别是,您可以在一个线程上多次锁定临界区,但对于简单的std :: mutex则不然。如果您需要锁定的递归行为,请使用std::recursive_mutex std::lock_guard<std::recursive_mutex>

更新2:关键部分和互斥锁之间的详细差异被描述为here,性能比较为here

理由:最好尽可能使用标准定义的机制。如果您使用特定于平台的东西 - 将其包裹起来。因此,如果您害怕性能 - 使用锁定/解锁方法创建关键部分类(以满足BasicLocakable概念要求)并使用std::lock_guard<MyCriticalSection>

答案 4 :(得分:1)

关于使用RAII对象的其他答案是正确的,但我觉得值得用Boost.ScopeExit指出一个简单的方法。

#include <boost/scope_exit.hpp>
...
EnterCriticalSection(&cs);
BOOST_SCOPE_EXIT(&cs) {
        LeaveCriticalSection(&cs);
} BOOST_SCOPE_EXIT_END
// code that may throw an exception