web-dev-qa-db-ja.com

C ++ 11では、 `const`の意味はまだスレッドセーフですか?

私は最近遭遇しました Herb Sutterのビデオから C++ 11でconstおよびmutableの意味がどのように変更されたかについてbitwiseconst(およびthread-safe、結果として)従来の論理的にconst。

5年後、プログラマーはconstのこの新しい意味に移行しましたか?

新しいアプリケーションの作成中にこれを使用しようとしましたが、すべてのプライベートメンバーをミューテックスまたはスレッドセーフ(実装によって)で保護されているため、プライベートメンバーをミュータブルとしてマークしているようです(正しくありません(私は経験が浅く、これの基礎がありません)。

すべてのメンバー関数constとすべてのメンバー変数mutableをマークするようにスレッドセーフなアプリケーションを設計する際の良い習慣はありますか?

4
CK.

引用した動画は、上級者向けです。 Herb Sutterは、このオーディエンスを最善の方法でコンセンサスに導こうとしますcommunicate他の人々へのこれらのキーワードの意図この時代のスレッドセーフになることを切望するすべて

したがって、このビデオに完全にスレッドセーフなコードを書くために知っておく必要があるすべての内容が含まれているとは期待しないでください。


すべてのプライベートメンバーをミュータブルまたはスレッドセーフ(その実装によって)で保護されているため、すべてのプライベートメンバーをミュータブルとしてマークしています。これは適切に感じられません(経験が浅く、これの根拠がありません)。

以下は、何が露骨に間違っているかの架空の例です。

_class Size
{
    mutable int x;
    mutable int y;
    // ...
public:
    void setSize(int newX, int newY) const // (first scream)
    {
        // modify members "x" and "y", "SAFELY!" (second scream)
    }
};
_

setSizeという名前の関数がconstである可能性がないため、関数のシグネチャが誤って叫びます。関数のコードの実装では、メンバー "x"と "y"をmutableとしてマークする必要がありますが、これも間違っていると思われます。

setSize関数のコードは関係ありません。関数の名前がその関数がオブジェクトの状態を変更することを示唆している場合は、constを付けないでください。関数からconstキーワードを削除するとします。これで、メンバー「x」と「y」でmutableキーワードを使用する必要がないことがわかりました。問題が解決しました。

言い換えると、constmutableの使用がどちらも直感に反する場合で、そのような扱いにくい使用がペアで発生する場合は、使用方法が間違っていることに疑いを持つ必要があります。

ただし、このビデオでは1つの例外的なケースについて言及しています。クラスに_std::mutex_メンバーが含まれている場合、ほとんどの場合、クラスをmutableメンバーとしてマークするのが適切です。説明はビデオをご覧ください。

正しく操作した経験があれば、直感に頼って自然に見えるかどうか、自然は正しいということを確認できます。

関数の名前がオブジェクトの状態を変更してはならないことを示している場合は、constでマークする必要があり、内部のコードはmadeである必要がありますthread-safe、by notスレッドに対して安全でない操作を実行しています

これは、上記のリンク先のビデオで表現されている考え方です。スレッドセーフになると、コードのユーザー(自分自身、または仲間のチームメイト)は、特定の機能すべきではないが特定のことを行うことを期待します

ビデオはこれらの例に言及しています:

  • nobody expectであるため、bool operator == (const T& other) constthisまたはotherを変更しないでください。何でも変更するための比較。 (これは「副作用なし」と呼ばれます。)
  • otherの同じインスタンスが2つのスレッドに渡され、各スレッドがそれをコピーコンストラクターに渡すため、class T { public: T(const T& other) {...} };otherを変更することはありません。

このコードはどうですか?

_class Size
{
    const int x;
    const int y;
    // ...
public:
    Size(int init_x, int init_y)
        : x(init_x), y(init_y)
    {
    }
};
_

このコードはさらに優れています。メンバーでのconstの正しい使用法を示しています。

ただし、特定の方法でSizeクラスを使用することはできません。たとえば、割り当て演算子を使用してSizeの既存のインスタンスを上書きすることはできません。言い換えると、Sizeクラスを実装する際のベストプラクティスに従って、Sizeを使用する他のソースコードを再設計する必要がある場合があります。これは、C++プロジェクトにとってconst-nessを重要な考慮事項とする「伝染性の問題」です。

9
rwong

スレッドセーフアプリケーションを設計するときに、すべてのメンバー関数をconstにマークし、すべてのメンバー変数を変更可能にするのは良い習慣ですか?

いいえ、それはnot良い習慣です。

Constメンバー関数は、関数が呼び出されたオブジェクトを変更しないことを通知します。オブジェクトは変更されないため、外部ロックなしで複数のスレッドから関数を呼び出しても安全です。

ただし、constメンバー関数が唯一のスレッドセーフ関数であるとは限りません。他の関数もスレッドセーフにすることができます。
const修飾子を使用して変更関数をスレッドセーフとしてマークすると、誤ったシグナルが送信されます。

constキーワードの意味はまだ「論理的にconst」です。論理的なconstnessがスレッドの安全性などを考慮する必要があるということだけです。

すべての「論理的にconst」とは、クラスのパブリックインターフェイスの観点からは、const関数のように見えることを意味します。これは良い概念です。クラスのパブリックインターフェイスが、プログラムの他の部分に違いをもたらす唯一のものだからです。私たちのconst関数はいくつかの情報をキャッシュに保存したり、ビット単位の状態を別の方法で変更したりするかもしれませんが、それは実装の詳細です:外部コードがビット単位ではないことを外部コードが認識できない場合const、次に、これをconstとマークする必要があります-これを可能にするために、一部のメンバーがmutableとマークされている可能性があります。

C++ 11とそのマルチスレッド機能により、この定義はより複雑になります。関数が本当にビット単位のconstである場合、複数のスレッドから同時に呼び出すことは自動的に安全です。これは、スレッドセーフではないすべての関数が自動的にnot論理的にconstであることを意味します。これは、外部コードの観点から、ビット単位のconst関数とは異なる動作をするためです。 。ビット単位のconst関数はスレッドセーフです。

したがって、コード内でconstとマークされている関数がスレッドセーフであることを確認する必要があるのは事実ですが、その逆は当てはまりません。スレッドセーフであるが論理的にはない関数を使用することは完全に合法ですconstその他の理由。

つまり、コードがconst以外の関数を呼び出す場合、そのコードは関数がnotスレッドセーフであると想定する必要があります。同時に呼び出す必要がある場合、個々の呼び出しは、外側のスコープ内のミューテックスによって保護する必要があります。現時点では関数がスレッドセーフである場合がありますが、これは実装の詳細であり、関数のシグネチャを変更せずに変更できます。

一方、関数isconstを非スレッドセーフに変更すると、関数のコントラクトが壊れます。

0
John Gowers