3

この質問に関連しているが、回答されていない質問があります。

ブーストshared_mutex(複数の読み取り/ 1つの書き込み)の例?

操作がメンバー関数内でスコープされている場合、排他ロックがどのように機能するかを理解しています。私の質問は、参照による戻り関数はどうですか?次のことを考慮してください(疑似コード):

class A {
    shared_mutex _mutex;
    std::string _name;

public:
    const std::string& name() const {shared_lock(_mutex); return _name;}
}

次に、コードで次のようなことをするとします。

A obj;
if (obj.name().length() >0) { ... };

私の腸は、length()関数が呼び出されるまでにミューテックスがすでにスコープ外になっているため、これはスレッドセーフではない可能性があると言っていますが、わかりません。

オブジェクトをスレッドセーフにしようとしている場合、全体像で質問していると思いますが、参照によって戻ることを完全に避ける必要がありますか?それは誰かがこのようなことをすることを可能にしませんか?

A obj;
std::string& s = obj.name();
(at this point lock is out of scope)
s = "foo";  // does this change the original object's member since it is a reference?
4

3 に答える 3

2

が戻っmutexた後に解放され、別のスレッドが呼び出し前または呼び出し中に変更を開始する可能性があり、の真のブランチに入る前に状態が変更される可能性があるため、スレッドセーフではありません。name()_namestd::string::length()_name{...}if

オブジェクトをスレッドセーフにするには、がロックされているときにすべてのアクセスが_name発生するようにします。mutexこれは、への参照が呼び出し元に返されないこと、またはこのコールバックが将来の非同期のアドレスをキャッシュする可能性があるため_name、のメンバー関数に提供されるコールバック(元のコードに投稿されていない架空のメンバー関数)に渡されないことを保証することを意味します、 使用する。A_name

代わりに、値で返すか渡します(そして_name、ミューテックスがロックされたときのコピーを作成します)。

// Must be mutable to be modifiable
// in a const member function.
mutable shared_mutex _mutex;

std::string name() const
{
    // Must not create a temporary shared_lock,
    // otherwise the lock will be released immediately.
    // So give the shared_lock a name.
    shared_lock lk(_mutex);
    return _name;
}
于 2013-03-25T20:35:10.383 に答える
1

この関数の遅延を変更するだけです。

const std::string& name() const ...

これに。

std::string name() const ...

次に、文字列のコピーを返します。 (そしてそれはコピーなので、そうである必要はありませんconst

そのコードはスレッドセーフであり、コンパイラーの最適化によってその安全性が維持されます。

于 2013-03-25T20:39:45.143 に答える
0

おそらく、パフォーマンス上の理由から(プレーンミューテックスの代わりに)shared_mutexを使用していますが、文字列のコピーにはコストがかかります。また、おそらく、中括弧内のコードif (obj.name().length() >0) { ... }は文字列をさらに操作する予定です。この場合、操作全体のミューテックスを取得する必要があります。そうしないと、競合状態に陥ります。(たとえば、コピーnameしてその長さを取得し、その間に他の誰かが短縮nameして長さ0にします。中括弧内のコードは、の長さについて誤った仮定をしnameます。)

可能であれば、文字列を操作するコードをのメンバー関数にすることを検討してくださいclass A

class A {
  shared_mutex _mutex;
  std::string _name;

public:
   rettype my_operation() {
     shared_lock lk(_mutex);
     if (_name.length() >0) { ... };
   }
};

他のオプションもありますが、それらはすべて、不変の保持に依存している期間全体にわたって共有ロックを保持することを含みます。

于 2013-03-25T21:56:31.720 に答える