C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[14]: ヘッダでスレッドセーフなシングルトン


(過去ログ 126 を表示中)

[トピック内 17 記事 (1 - 17 表示)]  << 0 >>

■74661 / inTopicNo.1)  ヘッダでスレッドセーフなシングルトン
  
□投稿者/ キム (38回)-(2015/01/21(Wed) 17:51:38)

分類:[C/C++] 

2015/01/22(Thu) 18:17:49 編集(投稿者)
開発環境: Visual C++ 2010 / Windows 7

お世話になります。

ヘッダファイルで提供するクラステンプレートがありまして、このテンプレート内部からのみ使う
シングルトンクラスがあります。
(クラステンプレートの動作を高速化するためのプールです)

そして、このシングルトンクラスの生成をスレッドセーフにしたいのです。
提供するクラステンプレートがヘッダファイルのみで提供する形式なのでヘッダファイルのみで
記述したいと思っています。
そこで、提供するクラステンプレートと同じヘッダファイルに下記のように記述しました。

#頑張って考えたんですけど、自己流なので致命的な穴があるかもしれません。
#逆に既知のアイデアであって、それの下手な実装という可能性もあります。

class MyPool
{
    MyPool()
    {
        // いろいろ処理...
    }

    MyPool(const MyPool& rhs);                      // コピー禁止
    const MyPool& operator =(const MyPool& rhs);    // 代入禁止

public:

    static MyPool& GetInstance()
    {
        static MyPool* volatile pInstance;

        // 高速化のためにpInstanceが0であることを最初に確認
        if (!pInstance)
        {
            // 実体を動的に生成(スレッド競合があれば複数生成されるかもしれない)
            MyPool* pTmp = new MyPool();

            // そこでCASでアトミックにpInstanceに設定(設定できるのは最初の1スレッドだけ)
            if (InterlockedCompareExchangePointer(reinterpret_cast<volatile PVOID*>(&pInstance), pTmp, 0) != 0)
            {
                // 失敗したら既に先行スレッドがpInstanceに実体を設定した後ということ。
                // この実体は不要なので破棄します。
                delete pTmp;
            }
        }

        return *(static_cast<MyPool* const volatile &>(pInstance));
    }

    // 各種実装...

};

※このコードはMyPoolのコンストラクターが例外を送出しないことを前提としています。

とりあえず正常に動作しているように見えますが、何点か疑問点と問題があります。

1.GetInstance()内のpInstanceは初回に呼ばれたときに必ず 0 であることを期待しています。
  JIS X3014:2003 6.7の4項によると、『静的記憶期間を持つ全ての局所オブジェクトは、そのゼロ初期化を
  その他の全ての初期化が起きる前に実行する』とあるので、0 であるか比較するのは問題ないと考えています。
  また、ゼロ初期化がスレッド競合により複数回発生することもないと考えています。
  この解釈で大丈夫でしょうか?

2.実体を動的に確保しているので、デバッグ時に Visual Studio にメモリーリークがあると怒られてしまいます。
  出来れば動的な確保はしたくはないのですが、動的な確保なしにスレッドセーフにする方法を思いつけませんでした。
  プロセス終了時に解放されるはずなので問題はないと思いますが、解消できる方法があれば解消したいです。
  お知恵をお貸しいただけると嬉しいです。

3. volatile 修飾をつけるべきかどうか迷っています。
  最適化による弊害を防ぐためにポインター変数自体にvolatile 修飾を付けています。
  また、return 時にもポインター変数を一旦 const volatile な参照にキャストしています。
  Visual C++ 2010 では何もつけなくてもリリースビルドで正常に動作しますし、
  実際には不要ではないのかとも思っています。
  でも根拠がないので念のために修飾しています。
  ご意見を聞かせていただけると嬉しいです。

または、『こんな方法じゃ根本的ダメだ』等ありましたらヒントやキーワードだけでも結構ですので、
ご教示いただけると嬉しいです。

1/22 18:17 誤記の修正と例外についての制限事項を追記しました。

引用返信 編集キー/
■74665 / inTopicNo.2)  Re[1]: ヘッダでスレッドセーフなシングルトン
□投稿者/ Azulean (414回)-(2015/01/21(Wed) 22:30:50)
2015/01/21(Wed) 22:34:34 編集(投稿者)

回答でなくて申し訳ないのですが、参考事例として見かけたものです。

http://qiita.com/MasayaMizuhara/items/ee067e513b8842edce0a


// 私自身はちゃんと検証できていないのでダメだったらすみません。
引用返信 編集キー/
■74668 / inTopicNo.3)  Re[2]: ヘッダでスレッドセーフなシングルトン
□投稿者/ キム (39回)-(2015/01/22(Thu) 10:21:30)
2015/01/22(Thu) 10:24:36 編集(投稿者)

No74665 (Azulean さん) に返信

Azuleanさん、お返事ありがとうございます。

教えていただいたサイトとても参考になりました。
特に解決策1は『静的記憶期間を持つ名前空間有効範囲のオブジェクトの初期化』を利用してプログラムがまだシングルスレッド
であると想定できる main() の前で 初期化するのがスマートだと思いました。
#私は初期化タイミングが自分で制御できる状態では、まだシングルスレッドである状態で手動でSingleton::getInstance()を
#呼び出すようなコードを書いていました。

ただ残念ながら、今回は提供するヘッダファイルのみで解決しなければならないのでこの解決策1は使えないように思います。
解決策2はSingleton::getInstance()を呼び出す前に最初に1回だけ呼び出す初期化関数を用意するということだと思いますが、
呼び出すのに適切なタイミングが無く今回は使えないのです。

でも勉強になったので嬉しいです。
ありがとうございます。

1/22 10:25 すみません、誤字を修正しました。
静的記憶機関 -> 静的記憶期間
引用返信 編集キー/
■74684 / inTopicNo.4)  Re[1]: ヘッダでスレッドセーフなシングルトン
□投稿者/ キム (40回)-(2015/01/22(Thu) 18:27:23)
なんとか頑張って動的な確保なしにスレッドセーフに出来ました。

class MyPool
{
    MyPool()
    {
        value_ = 0;
        // いろいろ処理...
    }

    MyPool(const MyPool& rhs);                      // コピー禁止
    const MyPool& operator =(const MyPool& rhs);    // 代入禁止

    static const long INIT_NONE = 0;                // 未初期化。この値は0であること
    static const long INIT_INITIALIZING = 1;        // 初期化中(初回のGetInstanceImpl呼び出し中)
    static const long INIT_COMPLETED = 2;           // 初期化済み

    // シンプルなスレッドセーフではないシングルトンインスタンス取得メソッド本体
    static inline MyPool& GetInstanceImpl()
    {
        static MyPool instance;

        return instance;
    }

public:

    // ロックフリーでスレッドセーフなシングルトンインスタンス取得
    static MyPool& GetInstance()
    {
        static volatile long initStat;

        if (initStat != INIT_COMPLETED)
        {
            // CASでアトミックに『未処理状態なら初期化中状態にする』
            if (InterlockedCompareExchange(&initStat, INIT_INITIALIZING, INIT_NONE) == INIT_NONE)
            {
                // ここに入れるのは未処理状態 -> 初期化中状態に変更出来た1スレッドだけです。
                MyPool& instance = GetInstanceImpl();
                InterlockedExchange(&initStat, INIT_COMPLETED);
                return instance;
            }
            else
            {
                // ここに入るのは競合で負けて初期化中状態に出来なかったスレッドです。
                // 別スレッド(初期化中状態に出来た唯一のスレッド)が初期化を完了させるまで待ちます。
                while (initStat != INIT_COMPLETED) {}
            }
        }

        return GetInstanceImpl();
    }
};

※このコードはMyPoolのコンストラクターが例外を送出しないことを前提としています。

1.やはりゼロ初期化が競合しないことを前提にしていますが、大丈夫だと判断しました。
  根拠は JIS X3014:2003 8.5の6項に『静的記憶期間を持つオブジェクトは、プログラム開始時に、
  その他の全ての初期化に先行してゼロ初期化されなければならない』と明記されているからです。
  実際にはプログラムロード時にゼロ初期化されていると予想しています。

2.また、動的な確保を無くしたので Visual C++ 2010 に怒られなくなりました。
  GetInstanceImpl()はスレッドセーフではないシングルトンオブジェクト取得関数です。
  GetInstance()内でCASによってアトミックにステータスの比較と更新を行うことで、GetInstanceImpl()
  の初回の呼び出しで競合を起こすことを防いでいます。

これで一応の目的は果たせましたが、もう少し検討から解決としたいと思います。

#実行速度を計ったらシンプルなスレッドセーフではない実装より速いです。不思議??

引用返信 編集キー/
■74704 / inTopicNo.5)  Re[2]: ヘッダでスレッドセーフなシングルトン
□投稿者/ επιστημη (118回)-(2015/01/23(Fri) 22:19:34)
外してるよな気がして、これがあなたの欲するものなのかは自信がないのですが...

Visual Studio 2012 以降でしたら、call_once で"絶対に一度しか呼ばれない"ことを保証できます。

https://msdn.microsoft.com/en-us/library/hh921437.aspx

引用返信 編集キー/
■74854 / inTopicNo.6)  Re[3]: ヘッダでスレッドセーフなシングルトン
□投稿者/ キム (41回)-(2015/02/02(Mon) 18:14:29)
No74704 (επιστημη さん) に返信

επιστημη さん、お返事ありがとうございます。
返信が大変に遅くなってしまいごめんなさい。

> Visual Studio 2012 以降でしたら、call_once で"絶対に一度しか呼ばれない"ことを保証できます。
>
> https://msdn.microsoft.com/en-us/library/hh921437.aspx

はい、求めているものは初期化がスレッドセーフなシングルトンの実装であり、そのために、
"絶対に一度しか呼ばれない"コードを書きたいのです。
そして、今回はそれをC++03(Visual Studio 2010)で実現したいのです。

ご教示いただいた方法は C++11 で追加されたものなので今回は使えませんが、とても勉強になりました。
興味がわいたので調べてみましたが、 C++11 では局所的な静的変数の初期化が絶対に一度しか行われない
ことが保証されていたり、とても便利になっていますね。
調べるきっかけを与えてくださってありがとうございます。
引用返信 編集キー/
■74856 / inTopicNo.7)  Re[4]: ヘッダでスレッドセーフなシングルトン
□投稿者/ Atata!! (5回)-(2015/02/02(Mon) 20:45:24)
2015/02/02(Mon) 20:50:53 編集(投稿者)
VC++固有の処理で良いなら、__declspec(selectany)を使うことができます。

class MyPool
{
    static MyPool __instance;

    MyPool()
    {
        // いろいろ処理...
    }

    MyPool(const MyPool& rhs);
    const MyPool& operator =(const MyPool& rhs);

public:
    static MyPool& GetInstance()
    {
        return __instance;
    }
};

__declspec(selectany) MyPool MyPool::__instance;

引用返信 編集キー/
■74858 / inTopicNo.8)  Re[5]: ヘッダでスレッドセーフなシングルトン
□投稿者/ キム (42回)-(2015/02/03(Tue) 10:37:04)
No74856 (Atata!! さん) に返信

Atata!!さん、お返事ありがとうございます。

__declspec(selectany)知りませんでした。
本来は複数定義となってしまうからヘッダファイルでは出来ないはずの『静的クラスメンバー変数の実体定義』
を可能とする機能ですね。
複数のソースファイルでincludeしてみましたが、リンクエラーにならずちゃんと1つの実体に解決されました。
便利です。

クラススコープの静的変数さえ持てれば(早期に初期化されるので)スレッド競合はありませんし、今回は、
『ヘッダファイルで提供するクラステンプレートと、そのヘッダファイルに記述され、クラステンプレート
内部からのみ使うシングルトンクラス』なので、異なる翻訳単位間の初期化順問題もありません。
実際に4つのスレッドから呼び出すテストをしてみましたが問題なく動作しました。

素敵な解決方法を教えてくださってとても嬉しいです。
ありがとうございます。
引用返信 編集キー/
■74859 / inTopicNo.9)  Re[6]: ヘッダでスレッドセーフなシングルトン
□投稿者/ キム (43回)-(2015/02/03(Tue) 12:10:58)
2015/02/05(Thu) 15:54:36 編集(投稿者)
2015/02/03(Tue) 12:12:52 編集(投稿者)

まとめです。

ヘッダファイルのみでスレッドセーフなシングルトンクラスを実現する方法

■局所的な静的変数(関数内のstatic変数)とCAS(Compare And Swap)を使う方法
ヘッダファイルのみでは『静的クラスメンバー変数の実体定義』は困難なので関数内のstatic変数を使います。
関数内のstatic変数は最初に関数が呼び出された時点で初期化されますが、再入呼び出しされた場合の動作は
未定義となっています。
そのためスレッドセーフではないので、CASを使ってスレッドセーフを実現します。
#今回はCAS等のアトミックな操作にはWindows APIを利用しています。
#同様なAPIは他のOSにもあると思いますので、他のOSでも実現可能だと思います。

その1
No74661 で最初に提示した方法です。
関数内のstatic変数としてポインターを持ち、初回呼び出し時に動的に実体を生成します。
スレッドセーフとなるようにCASで振り分けます。

欠点
newで動的に実体を生成していますが、この実体はdeleteされません。
そのため、デストラクターは呼ばれませんし、メモリーリークと検出されてしまいます。
ただし、プロセス終了時にOSが解放しますのでデストラクターでの処理がないのであれば問題はありません。
また、コンストラクターは複数回呼ばれる可能性があるので、『1つしかない資源を占有』するような処理を
コンストラクターに記述することは出来ません。

その2
No74684 で提示した方法です。
よく使われる関数内のstatic変数として実体を持つ方法です。
(提示したコード内の GetInstanceImpl関数)
このままではスレッドセーフではないので、GetInstanceImplはprivateとして、
安全に呼び出すためのラッパー GetInstance() を公開しています。
GetInstance() の役割は CASを利用することで 初期化シーケンス中は GetInstanceImpl() を絶対に1回しか呼ばないようにすることです。

プロセス終了前にデストラクターも呼ばれますし、特に欠点はないと思いますが多少実装が複雑です。

2/5 追記
このコードはVisual C++ 2005以降でビルドし、Windows上で実行した場合のみ安全です。
それ以外では、メモリバリアに関する考慮が必要になる場合があります。
後続の投稿を参照してください。

■ヘッダファイルのみで『静的クラスメンバー変数の実体定義』を実現する方法

静的クラスメンバー変数(クラススコープの静的変数)は早い段階で初期化されるのでスレッド競合が発生しません。
よって、静的クラスメンバー変数を使えばスレッドセーフが実現できることになります。
ですが通常の方法ではヘッダファイルでは『静的クラスメンバー変数の実体定義』は出来ないです。
それを実現する方法です。

その1
No74856 でAtata!!さんがご提示してくださった方法です。
Visual C++固有の機能となりますが、__declspec(selectany) を使えばヘッダファイルのみで
『静的クラスメンバー変数の実体定義』が可能です。

その2
クラステンプレートを利用すれば、__declspec(selectany)と同様にヘッダファイルのみで
『静的クラスメンバー変数の実体定義』が可能と思われます。
(具現化される型ごとに静的クラスメンバーの実体が定義されるはず)
が、今回は試していません。

注意点
静的クラスメンバー変数を用いた場合、スレッド競合は解決できますが、『異なる翻訳単位間の初期化順問題』
が発生します。
今回のケースでは『異なる翻訳単位間の初期化順問題』は発生しないですが、それが発生するようなケースに
この方法を用いる場合はさらに工夫が必要となります。

■その他
C++ 11 であれば No74704 でεπιστημη さんが示してくださった方法が使えますし、
(準拠していれば)局所的な静的変数の初期化が絶対に一度しか行われないことが保証されて
いたりするのでもっと簡単に実現できると思われます。

ヘッダファイルのみという条件を外せば、 No74665 でAzuleanさんが教えてくださったサイトが
参考になります。

私の解釈が間違っている点などがありましたらご指摘ください。
問題が無いようなら解決にチェックをつけたいと思います。

2/3 12:13 すみません、誤字修正しました。
引用返信 編集キー/
■74875 / inTopicNo.10)  Re[7]: ヘッダでスレッドセーフなシングルトン
□投稿者/ キム (44回)-(2015/02/05(Thu) 09:25:29)
あれから局所的な静的変数+CASを使う方法( No74684 )と __declspec(selectany) を使う方法( No74856 )
の両方を実際のシステムに組み込んで動作確認を行いましたがどちらも問題なく動作しました。
最終的に、今回はシンプルさを優先して __declspec(selectany) を使う方法を採用させていただきました。

GetInstance() を介して簡単な処理を呼び出したときの処理時間(10億回繰り返し)も計ってみました。

スレッドセーフではない単純なシングルトン実装 2.1秒
静的メンバー変数 + __declspec(selectany) 2.1秒
局所的な静的変数 + CAS 1.9秒

スレッドセーフではない単純なシングルトン実装とほぼ同じなので、スレッドセーフにするためのオーバーヘッド
は無いと思います。
局所的な静的変数 + CAS だけ僅かに速いですが、これはたまたま全体的な最適化がよく効いたためだと考えています。

その他まとめはすぐ上の No74859 にあります。
これにて本件は解決とさせていただきたいと思います。
ありがとうございます。
解決済み
引用返信 編集キー/
■74876 / inTopicNo.11)  Re[8]: ヘッダでスレッドセーフなシングルトン
□投稿者/ なちゃ (26回)-(2015/02/05(Thu) 09:44:19)
今更ですが、スレッドセーフのその2は、厳密にはスレッドセーフになってない気がします。
Visual C++でx86系前提なら現実問題としては関係ない気はしますが。

C++のvolatileってメモリフェンス機能はないはずなので、初期か状態の確認と初期化済みオブジェクトの取得で強豪が発生し、C++仕様的には未定義の動作になる気がします。

解決済み
引用返信 編集キー/
■74879 / inTopicNo.12)  Re[9]: ヘッダでスレッドセーフなシングルトン
□投稿者/ キム (45回)-(2015/02/05(Thu) 11:31:30)
No74876 (なちゃ さん) に返信

なちゃさんお返事ありがとうございます。

CPUのアウトオブオーダー実行やコンパイラの最適化によって予想外の動作が行われる可能性があるということでしょうか?

調べてみたら下記の記事を見つけました。

https://msdn.microsoft.com/ja-jp/library/bb310595(VS.85).aspx

この資料によると、
・x86アーキテクチャが読み込み同士や書き込み同士のリオーダーを行わない。
・Windows の Interlocked系のすべての関数には、完全なメモリーバリアが使用されている。
・Visual C++ 2005以降では、volatile 変数の読み取りには Read-Acquire バリア、書き込みには Write-Release バリアが適用される。
となっています。

そのため、スレッドセーフのその2( No74684 のコード)は、『Visual C++ 2005以降でビルドし、Windows上で実行する場合だけ
確実に動作する。それ以外の組み合わせでは、未定義の動作となる可能性がある。』ということでしょうか?

奥が深いですね。勉強になります。

#ごめんなさい、疑問点が出たので一旦解決を解除します。
引用返信 編集キー/
■74884 / inTopicNo.13)  Re[10]: ヘッダでスレッドセーフなシングルトン
□投稿者/ 774RR (220回)-(2015/02/05(Thu) 14:13:21)
ここでも過去にこんな議題が
http://bbs.wankuma.com/index.cgi?mode=al2&namber=65737&KLOG=111

「メモリバリア」の初級解説
・ある1つの CPUcore が共有変数の値を修正する
・その修正結果は当該 CPUcore のキャッシュに留まり、共有されている主記憶に(直ちには)届かない
・キャッシュがフラッシュされるまで、他の CPUcore からは共有変数の値の修正が認知されない
という動作を許すような CPU が存在する (x86/x64 は該当しない)

もし仮に、このような動作しかないと「ロック」のようなことは不可能なので
「キャッシュでなく主記憶まで変更を確実に届ける命令」を
「プログラマがソースコードに記述することで」確実なロックを実現する必要がある
ような処理系は存在する : 大事なことなので繰り返すが x86/x64 はそうでない

どのような「メモリバリア」があるかはたとえば
http://yamasa.hatenablog.jp/entry/20090816/1250446250

C# の volatile はメモリバリアを兼ねるんだっけ?

メモリバリア(CPU の機能として、ある CPU が変数に書いた値が、他の CPU からどう観測されるか)
リオーダー(コンパイラ/CPU の機能として、プログラマの意図に反しない範囲での命令の順番の入れ替えを行う)
ってのは別の話。

No74879 の理解はそれであっていると思うよ。
引用返信 編集キー/
■74887 / inTopicNo.14)  Re[11]: ヘッダでスレッドセーフなシングルトン
□投稿者/ キム (46回)-(2015/02/05(Thu) 15:56:43)
774RRさん、お返事ありがとうございます。

奥が深いです。
今回はヘッダーだけで実装するために同期オブジェクトの実体が持てず、あまり深く考えずにロックフリー
に手を出したのですが、やけどする前にいろいろ理解できてよかったです。

> No74879 の理解はそれであっていると思うよ。

リンク先の先を辿っていったら、MSDNの記事(マルチプロセッサ環境下でのメモリ同期問題の解説、および
WinAPI / VisualC++ での解決策)
https://msdn.microsoft.com/en-us/library/ms686355(v=VS.85).aspx
があり、これも興味深く読ませていただきました。
おかげさまで今回の環境では安全であることに確信が持てました。

C++11はスレッド周りとかメモリモデル(?)とかが厳密になっていていいですね。
C++03にはスレッドという概念がないのだから仕方ないですが、やはり今回のような状況では迷ってしまいます。

> C# の volatile はメモリバリアを兼ねるんだっけ?

メモリバリアを兼ねるみたいですね。
C# 言語仕様 4.0 (VSインストールフォルダー/VC#/Specifications/1041/CSharp Language Specification.doc)
の 10.5.3 に詳しく書いてありました。

これで今度こそ解決です。
ありがとうございます。
解決済み
引用返信 編集キー/
■74896 / inTopicNo.15)  Re[12]: ヘッダでスレッドセーフなシングルトン
□投稿者/ yoh2 (4回)-(2015/02/06(Fri) 22:24:06)
C# の volatile にメモリバリア効果があるなら、

> ここでも過去にこんな議題が
> http://bbs.wankuma.com/index.cgi?mode=al2&namber=65737&KLOG=111

上記の No65894 で書いたサンプルでおかしな結果が起こることがないはず、
と思い、実験や調査を行ってみました。

もしかして、

> private static volatile bool[]  Locks = { false, false };

という書き方って、Locks 自体は volatile だけど、Locks[n] についてはそうではない、
とかなのかと思い、volatile bool[] の代わりに、 volatile bool の変数をふたつ
使うように変更してみたりもしましたが、VS 2012 の C# コンパイラでコンパイラ
しても相変わらずおかしな動きをするわけで。

そこで C# の言語仕様を当たってみました。
確かに順序の規定はありましたけど、完全なシーケンシャルバリアではないようです。

 - volatile フィールドの読み取り:それ以降のメモリ参照より先に行われることが保証されている。いわゆる acquire バリア。
 - volatile フィールドへの書き込み: それ以前のメモリ参照の後に行われることが保証されている。いわゆる release バリア。

といった規定のみ。つまり、volatile フィールドへの書き込み → 読み取り、とすると逆転の
可能性は残っていると考えるべきだと思いました。そうすれば辻褄があいますし。
例えば、

  volatile bool x;
  volatile bool y;

  ...

                 // ここより前のメモリ参照は (1) より前に行われることが保証されている
  x = true       // (1)
                 // ここの区間についての規定はない
  if (y)         // (2)
                 // ここより後のメモリ参照は (2)

とした場合、x への書き込みと y の評価が逆転。y を見てから x に代入
するといった動きをする可能性がある、と。

うーむ。C# でも volatile を付けたから無条件で安心、というわけにはいかないようです。

引用返信 編集キー/
■74897 / inTopicNo.16)  Re[13]: ヘッダでスレッドセーフなシングルトン
□投稿者/ yoh2 (5回)-(2015/02/06(Fri) 22:26:40)
ごめんなさい。脱線気味の話題にもかかわらず解決済みチェックを外してしまいました。
チェック入れ直しておきます。
解決済み
引用返信 編集キー/
■74918 / inTopicNo.17)  Re[14]: ヘッダでスレッドセーフなシングルトン
□投稿者/ キム (47回)-(2015/02/09(Mon) 15:43:19)
No74897 (yoh2 さん) に返信

yoh2さん、お返事ありがとうございます。
検証までしていただいてありがとうございます。

仕様書を読み返してみると確かに、volatile変数の読み取りに Read-Acquire バリア、書き込みに Write-Release バリアが適用される
ことしか明記されてないです。
勘違いしてごめんなさい。

結局、Visual C++ 2005以降の volatile と同じ仕様みたいですね。
私はC#も使うので勉強になります。
C#では、なるべくメモリモデルを意識しなくて済むような書き方をしたいですが、どうしても必要な場合は注意して書こうと思います。

検索していたら下記の記事を見つけました。
後で閲覧される方の参考にもなると思うので、はっておきます。

C# メモリ モデルの理論と実践
https://msdn.microsoft.com/ja-jp/magazine/jj863136.aspx

C# メモリ モデルの理論と実践(第2部)
https://msdn.microsoft.com/ja-jp/magazine/jj883956.aspx

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -