1

ご存知のように、コンパイラまたは CPU は、as-if ルールに従っている場合にのみ、必要に応じて実行を並べ替えることができます。たとえば、次のようなコードがあるとします。

C = A + B;
D = E + F;

コンパイラまたは CPU は のD = E + F前に実行される場合がありC = A + Bます。私はそれを理解することができます。

今日、同僚が C++ でログ ライブラリを構築しようとしました。彼のアイデアは、コンストラクタとデストラクタを使用して、operator<<().

基本的に、彼はそのような種類のクラスを提供しました:

class Log
{
public:
    Log() { streamObj << "start: " << getCurrentTime() << endl; }
    ~Log() { streamObj << "end: " << getCurrentTime() << endl; }
};

今、私はログ ライブラリのユーザーです。私の同僚は、以下のようにライブラリを使用できると私に言いました:

void func()
{
    Log log;
    // do something1
    // do something2
    // do something3
    return;
}

したがって、最初の行が実行されると、コンストラクターが呼び出されるため、ログで「開始」を取得できます。そして、関数が戻ると、のデストラクタlogが呼び出されるのでend、ログに記録されます。オブジェクトの助けを借りてlog、関数の開始と終了を明確に見つけることができます。

クリアで素晴らしいですね。

ただし、投稿の冒頭で述べたように、マシンは必要に応じて並べ替えを行う場合があります。そのため、 のコンストラクターがlog思ったよりも遅く呼び出されたり、 のデストラクタがlog思ったよりも早く呼び出されたりして、logが期待どおりに機能しない可能性があるかどうか疑問に思っています。つまり、コードはfunc上記のように見えましたが、コンパイルまたは実行すると、実際の順序は次のようになりました。

// do something1
Log log;
// do something2
// call the destructor of `log`
// do something3
return

ところで、クラス内のストリームはLog、ファイル、共有メモリ、TCP ソケットなど、別の場所に送られます。

それで私は合理的ですか?それとも、この種の並べ替えは決して起こらないのでしょうか? それが起こる可能性がある場合、この種の並べ替えを禁止する手法や、関数の開始と終了を通知できる使用可能なログ ライブラリを提供する手法はありますか?

実際、C++11 で や などの新しいテクニックを聞いたことがstd::atomicありstd::atomic_thread_fenceます。私の理解では、この種の並べ替えが可能である場合、必要なものは... フェンスでしょうか?

class Log
{
public:
    Log() {
        streamObj << "start: " << getCurrentTime() << endl;
        // build a fence here!
    }
    ~Log() { streamObj << "end: " << getCurrentTime() << endl; }
};

可能かどうかは本当にわかりません...

副作用/観察可能な動作について

私の理解では、これは副作用/観察可能な動作です。

A = B + C

なんで?の値Aが変わるからです。

では、次のようにコーディングするとどうなるでしょうか。

void func()
{
    Log log;
    A = B + C;
}

したがって、順序は次のようになります。

  • のコンストラクタlog
  • A = B + C
  • のデストラクタlog

ただし、順序が次のようになる場合:

  • A = B + C
  • のコンストラクタlog
  • のデストラクタlog

それでいいと思います。なんで?A副作用/観察可能な動作に関するの値は変更されないためです。どの順序を取っても、その値は常に になりますB + C

私は正しいですか?私が正しければLog、期待どおりに機能しないことを意味すると思います。

アップデート

A = B + Cの値が変更されるという副作用がありますが、これはA観察可能な動作ではありません。

4

0 に答える 0