gpt4 book ai didi

c++ - 如何返回作用域锁?

转载 作者:IT老高 更新时间:2023-10-28 23:00:46 25 4
gpt4 key购买 nike

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

我有一个类有一个 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();
}

这个想法是 LockedFunc1LockedFunc2 将在持有锁的情况下被调用。 lock 的析构函数将解锁 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

您可以使用锁定的包装器类型选择性地授予对该类型接口(interface)部分的访问权限。

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 是引入额外开销/争用或锁定/并发错误和错误的好方法。在某些情况下,这是一个值得考虑的简单替换。

当正确性、性能和/或其他限制至关重要时,我认为抽象或封装这些复杂性是非常有意义的,即使它会花费一些语法噪音或抽象层。我这样做是因为引入重大更改太容易了——即使我已经编写并维护了整个程序。对我来说,这是一个更复杂的可见性案例,如果使用得当,也是非常明智的。

一些例子

向下滚动到 main - 这个示例相当杂乱无章,因为它同时展示了多种方法:

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

关于c++ - 如何返回作用域锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8089696/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com