どうすればいいですか?
class t_scope_lock {
public:
t_scope_lock(MyClass& myClass);
...
private:
boost::scoped_lock d_lock;
};
とこのタイプのミューテックスへのアクセスを許可するためのMyClass
:
代替1
一つのアプローチは、boost::scoped_lock
を有する型を作成することであろう。このクラスが具体的にMyClass
のために書かれている場合は、内部クラスMyClass::t_scoped_lock
として追加するだけです。
代替2
別のアプローチは、(カスタム)スコープロックのコンストラクタに変換することができスコープロックとともに使用するための中間体タイプを作成することであろう。次に、タイプは適合しているようにオプトインできます。多くの人がカスタムスコープロックを気に入らないかもしれませんが、あなたが望むように簡単にアクセスを指定し、適切な制御を行うことができます。
第三の選択
時にはそれがMyClass
のための抽象化レイヤを追加する方が良いでしょう。
{
boost::scoped_lock lock(f->GetScopedLock());
f->LockedFunc1();
f->LockedFunc2();
}
(4
は時々あなたが別のロックを使用することができます代替例:クラスが複雑な場合、これはあなたがどのように見えるの変種の多くを提供する必要がありますので、良い解決策はそうではありません内部と外部)。
#4から5
同様の代替は、あなたには、いくつかのケースでは、再帰や読み書きロックを使用することができます。あなたが選択種類のインターフェースの部分へのアクセスを許可するためにロックされたラッパー型を使用することができます
オルタナティブ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は、追加のオーバーヘッド/競合またはロック/同時エラーとバグを導入する良い方法です。場合によっては、それは考慮に値する単純な代替語です。
正確性、パフォーマンス、および/またはその他の制限が重要な場合は、構文的なノイズや抽象化レイヤーを要しても、その複雑さを抽象化またはカプセル化することは理にかなっていると思います。これは、プログラム全体を書いて管理していても、簡単に変更を導入することが容易であるためです。私にとっては、視認性のより精巧なケースであり、正しく使用されれば完全に賢明です。 main
まで
一部として
スクロール - このサンプルは、それが1にいくつかのアプローチを示しているのでかなり無秩序である:
#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;
}
これは別の問題を探して私はつまずいた。しかし、私に打撃を与えるのは、MyClassのロックアウト*を渡すことが、本当にあなたがやりたいことの反対です。代わりに、MyClassのメソッド "ExecuteAtomically"または "ExecuteLocked"を使用して、ロックを保持しているコンテキストで評価したいコードのチャンクを含むラムダ式を渡すことができます。私はBoost/C++でそれを行う最善の方法を見つけ出そうとしていますが、私よりも賢い人がチャイムに入るかもしれません。 –
@ChrisCleeland:これは問題について考えるとても興味深い方法です。 –
もう少し考えてみるといいと思います。 "Execute"メソッドはFunctorを定義して第1引数に "this"(または* this)をバインドできるように、Execute(boost :: function)のようなシグネチャを持つことができます。それが適切に動作すると推測すると、boost :: lambda(または新しい言語機能)を使用してファンクタの本体を移動させて、コールがある場所にあるようにすることはあまり多くの作業であってはなりません実行する()。私は現在の仕事リストの中でこれを試してみる場所を見つけ出すことができたと思っていましたが、私はそうしていませんでした。後で試してみてください。 –