它是安全的锁/范围防护实施吗?

时间:2014-05-22 04:44:19

标签: c++ multithreading

现在我从类中获得了线程安全字段的实现:

int A::GetValue() const
{
    _mutex.Lock();
    int temp = _value;
    _mutex.Unlock();
    return temp;
}

我想用这样的锁/范围保护实现替换它(LockGuard类只有构造函数/析构函数和Mutex * _mutex字段):

LockGuard::LockGuard(Mutex & mutex) : _mutex(&mutex)
{
    _mutex->Lock();
}

LockGuard::~LockGuard()
{
    _mutex->Unlock();
}

重构代码:

int A::GetValue() const
{
    LockGuard lockGuard(_mutex);
    return _value;
}

我突然意识到我不确定这是否是一个安全的实施方案。是否保证首先将_value的副本传递出函数,并且只有已经存在此副本的_mutex才会被解锁? 请不要提供C ++ 11替代实现示例 - 我有嵌入式系统,不幸的是不能使用它们。

3 个答案:

答案 0 :(得分:5)

这一行是个问题:

LockGuard(_mutex);

应该是:

LockGuard foo(_mutex);

否则它将超出范围并在方法的其余部分执行之前解锁您的互斥锁。 (您可以通过在LockGuard构造函数和析构函数以及调用方法中临时插入printf或类似函数来验证有问题的行为。)

除此之外你的锁定模式还不错。

答案 1 :(得分:4)

LockGuard的实施是可以的,但使用错误。随着声明

LockGuard(_mutex);

您正在创建一个临时LockGuard,它将在语句完成后销毁。

您的用法应为

LockGuard guard(_mutex);
return _value;

LockGuard guard(_mutex);将创建一个LockGuard对象,它将在构造函数中锁定互斥锁。当方法返回时,将调用析构函数,解锁互斥锁。而且您不再需要使用临时返回。

答案 2 :(得分:4)

也许这个程序帮助您想象会发生什么:

#include <iostream>

// Replaces the int so that we know when things happen
struct Int {
   Int() {
       std::cout << "Int::Int()" << std::endl;
   }
   ~Int() {
       std::cout << "Int::~Int()" << std::endl;
   }
   Int(const Int &x) {
       std::cout << "Int::Int(const Int&)" << std::endl;
   }
};

struct LockGuard {
   LockGuard() {
     std::cout << "Locking" << std::endl;
   }
   ~LockGuard() {
     std::cout << "Unlocking" << std::endl;
   }    
};

struct A {    
  Int getValue() const {
     LockGuard lockGuard;
     return _value;
  }    
  Int _value;    
};


int main() {
   A a;
   std::cout << "about to call" << std::endl;
   Int x=a.getValue();
   std::cout << "done calling" << std::endl;
}

导致

Int::Int()
about to call
Locking
Int::Int(const Int&)
Unlocking
done calling
Int::~Int()
Int::~Int()

最后要注意的是,您可能需要在属性声明中生成_mutex mutable,因为锁定和解锁通常是非const操作,否则将不允许在const方法中使用。