c++ 如何返回范围锁?

考虑一个帐户余额的集合.然后,您有一个复杂的功能,需要检查几个不同帐户的余额,然后调整几个不同帐户的余额.相对于集合的其他用户,操作需要是原子的.你有一个集合类,其主要工作是提供这种原子性.什么是“正确”的方式?

我有一个类有一个boost :: mutex成员.问题是,呼叫者可能需要在持有互斥体的同时执行一系列调用.但是我不想在互斥体之外给代码外的自由统治.

我想做的是这样的(伪代码):

class MyClass
{
 private:
  boost::mutex mLock;
 public:
  boost::scoped_lock& ScopedLock(return ScopedLock(mLock));
}

这样,呼叫者可以做到这一点:

MyClass f;
if(foo)
{
 boost::scoped_lock lock(f->GetScopedLock());
 f->LockedFunc1();
 f->LockedFunc2();
}

这个想法是LockedFunc1和LockedFunc2将被锁定.锁定的析构函数将解锁f-> mLock.

我有两个基本问题:

1)我该怎么做?

2)这是明智的吗?

注意:这与这个类似的问题完全不一样:return a boost::scoped_lock.

我该怎么做?

替代方案1

一种方法是创建一个具有boost :: scoped_lock的类型:

class t_scope_lock {
public:
  t_scope_lock(MyClass& myClass);
  ...
private:
  boost::scoped_lock d_lock;
};

并为MyClass授予对此类型的互斥体的访问权限.如果这个类是专门为MyClass编写的,那么我只需将它添加为内部类MyClass :: t_scoped_lock.

备选方案2

另一种方法是创建一个中间类型,用于可以转换为(自定义)范围锁构造函数的作用域锁.那么类型可以选择,因为他们认为合适.很多人可能不喜欢自定义范围锁定,但它将允许您轻松地指定访问,并且具有良好的控制.

替代3

有时最好为MyClass添加一个抽象层.如果课堂很复杂,这不太可能是一个很好的解决方案,因为你需要提供很多类似的变体:

{
 boost::scoped_lock lock(f->GetScopedLock());
 f->LockedFunc1();
 f->LockedFunc2();
}

替代方案4

有时您可以使用另一个锁(例如内部和外部).

替代5

与#4类似,在某些情况下可以使用递归或读写锁.

备选方案6

您可以使用锁定的包装类型来选择性地授予对类型界面部分的访问权限.

class MyClassLockedMutator : StackOnly {
public:
    MyClassLockedMutator(MyClass& myClass);
// ...
    void LockedFunc1() { this->myClass.LockedFunc1(); }
    void LockedFunc2() { this->myClass.LockedFunc2(); }
private:
    MyClass& myClass;
    boost::scoped_lock d_lock; // << locks myClass
};

MyClass f;
MyClassLockedMutator a(f);

a.LockedFunc1();
a.LockedFunc2();

这是明智的吗?

请记住,我不知道您的程序的确切限制(因此,多种替代方案).

替代品#1,#2,#3和#6(虚拟)没有性能开销,并且在许多情况下具有边际额外的复杂性.然而,对于客户来说,它们在语法上是嘈杂的. IMO,强制正确性,编译器可以检查(根据需要)比最大限度地减少语法噪声更重要.

替代品#4和#5是引入额外开销/争用或锁定/并发错误和错误的好方法.在某些情况下,这是值得考虑的简单替代.

当正确性,性能和/或其他限制是至关重要的时候,我认为抽象或封装这些复杂性是完全有道理的,即使它花费一些语法噪声或抽象层.我这样做,因为它太容易引入突破性的变化 – 即使我已经编写并维护了整个程序.对我来说,这是一个更加精细的可见性的情况,如果使用正确,它是完美的.

一些例子

向下滚动到主 – 这个样本是相当混乱的,因为它演示了几种方法:

#include <iostream>
#include <boost/thread.hpp>

class MyClass;

class MyClassOperatorBase {
public:
    /* >> public interface */
    bool bazzie(bool foo);
protected:
    MyClassOperatorBase(MyClass& myClass) : d_myClass(myClass) {
    }

    virtual ~MyClassOperatorBase() {
    }

    operator boost::mutex & ();

    MyClass& getMyClass() {
        return this->d_myClass;
    }

    const MyClass& getMyClass() const {
        return this->d_myClass;
    }

protected:
    /* >> required overrides */
    virtual bool imp_bazzie(bool foo) = 0;
private:
    MyClass& d_myClass;
private:
    /* >> prohibited */
    MyClassOperatorBase(const MyClassOperatorBase&);
    MyClassOperatorBase& operator=(const MyClassOperatorBase&);
};

class MyClass {
public:
    MyClass() : mLock() {
    }

    virtual ~MyClass() {
    }

    void LockedFunc1() {
        std::cout << "hello ";
    }

    void LockedFunc2() {
        std::cout << "world\n";
    }

    bool bizzle(bool foo) {
        boost::mutex::scoped_lock lock(this->mLock);

        return this->imp_bizzle(foo);
    }

protected:
    virtual bool imp_bizzle(bool foo) {
        /* would be pure virtual if we did not need to create it for other tests. */
        return foo;
    }

private:
    class t_scope_lock {
    public:
        t_scope_lock(MyClass& myClass) : d_lock(myClass.mLock) {
        }

    private:
        boost::mutex::scoped_lock d_lock;
    };
protected:
    friend class MyClassOperatorBase;
private:
    boost::mutex mLock;
};

MyClassOperatorBase::operator boost::mutex & () {
    return this->getMyClass().mLock;
}

bool MyClassOperatorBase::bazzie(bool foo) {
    MyClass::t_scope_lock lock(this->getMyClass());

    return this->imp_bazzie(foo);
}

class TheirClassOperator : public MyClassOperatorBase {
public:
    TheirClassOperator(MyClass& myClass) : MyClassOperatorBase(myClass) {
    }

    virtual ~TheirClassOperator() {
    }

    bool baz(bool foo) {
        boost::mutex::scoped_lock lock(*this);

        return this->work(foo);
    }

    boost::mutex& evilClientMove() {
        return *this;
    }

protected:
    virtual bool imp_bazzie(bool foo) {
        return this->work(foo);
    }

private:
    bool work(bool foo) {
        MyClass& m(this->getMyClass());

        m.LockedFunc1();
        m.LockedFunc2();
        return foo;
    }
};

class TheirClass : public MyClass {
public:
    TheirClass() : MyClass() {
    }

    virtual ~TheirClass() {
    }

protected:
    virtual bool imp_bizzle(bool foo) {
        std::cout << "hallo, welt!\n";
        return foo;
    }
};

namespace {
/* attempt to restrict the lock's visibility to MyClassOperatorBase types. no virtual required: */
void ExampleA() {
    MyClass my;
    TheirClassOperator their(my);

    their.baz(true);

// boost::mutex::scoped_lock lock(my); << error inaccessible
// boost::mutex::scoped_lock lock(my.mLock); << error inaccessible
// boost::mutex::scoped_lock lock(their); << error inaccessible

    boost::mutex::scoped_lock lock(their.evilClientMove());
}

/* restrict the lock's visibility to MyClassOperatorBase and call through a virtual: */
void ExampleB() {
    MyClass my;
    TheirClassOperator their(my);

    their.bazzie(true);
}

/* if they derive from my class, then life is simple: */
void ExampleC() {
    TheirClass their;

    their.bizzle(true);
}
}

int main(int argc, const char* argv[]) {
    ExampleA();
    ExampleB();
    ExampleC();
    return 0;
}
相关文章
相关标签/搜索