2016-07-05 2 views
0

私は現在アトミックな読み書きをしていて、私の理解の壁を打っています。私は、変数への書き込み(例えば、インクリメントを介して)はアトミックでなければならないと理解していますが、変数の読み込みについてはわかりません。値を原子的に読み取る関数はありますか?

Windowsでは_InterlockedExchangeAdd、Linuxでは__sync_add_and_fetchとします。私は原子的にが更新される値を検索する関数を見つけることができません。今私はここに投稿する前に私の研究を行ったとAre C++ Reads and Writes of an int Atomic?は、読み取りはアトミックではないことを私に伝えます。

1)上記の関数を使用すると、どのように私は原子的にどうすればの値をと読み替えますか?

2)これらの関数を使用したくない場合、変数の現在の値を取得する関数で、「アトミック」変数を書き込む前にmutexをロックしたければ、最初にする必要がありますミューテックスをロックし、現在の値をコピーし、ミューテックスをロック解除してからコピーを返しますか?私はこれらのAPIを使用する必要があり、したがって、原子ヘッダーへのアクセスを持っていないコンパイラを使用しています

EDIT

+1

あなたは[''](http://en.cppreference.com/w/cpp/atomic/atomic)を調べましたか? – CoryKramer

+0

申し訳ありませんが、アトミックヘッダーを使用できないことを示すためにQを更新しました。 – Wad

+0

read-modify-writeを実行している場合は、操作全体がmutex内になければなりません。私が追跡しなければならなかった最悪のバグの1つは、読み込みがミューテックスにあって、その間にそれをリリースできると書かれていたと思った人でした。 – stark

答えて

1

答えが見つからないのは、(a)速く、(b)持ち運びできるようにする方法がないからです。それは依存しています:C + +またはC、コンパイラ、コンパイラのバージョン、コンパイラの設定、ライブラリ、アーキテクチャ...リストは続けています。ここで

は出発点である:

  • あなたが標準アトミックへのアクセス権を持っているか、そしてatomic_load()を使用している場合 - それは、ポータブルかつ高速です。
  • 標準アトミックがない場合は、CASを使用してください。たとえば、Windowsでは_InterlockedCompareExchange(,0,0)になります。 https://msdn.microsoft.com/en-us/library/ms686355(VS.85).aspxを参照してください。 Linuxでは__sync_val_compare_and_swap(, 0, 0)になります。 https://gcc.gnu.org/onlinedocs/gcc-4.4.3/gcc/Atomic-Builtins.htmlを参照してください。
  • 直接割り当てを使用する場合は、コードの実行場所を知っているエキスパートに確認する必要があります。

私は、CASが合理的な代替方法である理由を説明するかもしれないアセンブラコードのスニペットを持っていることがあります。あなたの計画は(2)ミューテックスを使用するための正しい

volatile long debug_x64_i = std::atomic_load((const std::_Atomic_long *)&my_uint32_t_var); 
00000001401A6955 mov   eax,dword ptr [rbp+30h] 
00000001401A6958 xor   edi,edi 
00000001401A695A mov   dword ptr [rbp-0Ch],eax 
    debug_x64_i = _InterlockedCompareExchange((long*)&my_uint32_t_var, 0, 0); 
00000001401A695D xor   eax,eax 
00000001401A695F lock cmpxchg dword ptr [rbp+30h],edi 
00000001401A6964 mov   dword ptr [rbp-0Ch],eax 
    debug_x64_i = _InterlockedOr((long*)&my_uint32_t_var, 0); 
00000001401A6967 prefetchw [rbp+30h] 
00000001401A696B mov   eax,dword ptr [rbp+30h] 
00000001401A696E xchg  ax,ax 
00000001401A6970 mov   ecx,eax 
00000001401A6972 lock cmpxchg dword ptr [rbp+30h],ecx 
00000001401A6977 jne   foo+30h (01401A6970h) 
00000001401A6979 mov   dword ptr [rbp-0Ch],eax 

    volatile long release_x64_i = std::atomic_load((const std::_Atomic_long *)&my_uint32_t_var); 
00000001401A6955 mov   eax,dword ptr [rbp+30h] 
    release_x64_i = _InterlockedCompareExchange((long*)&my_uint32_t_var, 0, 0); 
00000001401A6958 mov   dword ptr [rbp-0Ch],eax 
00000001401A695B xor   edi,edi 
00000001401A695D mov   eax,dword ptr [rbp-0Ch] 
00000001401A6960 xor   eax,eax 
00000001401A6962 lock cmpxchg dword ptr [rbp+30h],edi 
00000001401A6967 mov   dword ptr [rbp-0Ch],eax 
    release_x64_i = _InterlockedOr((long*)&my_uint32_t_var, 0); 
00000001401A696A prefetchw [rbp+30h] 
00000001401A696E mov   eax,dword ptr [rbp+30h] 
00000001401A6971 mov   ecx,eax 
00000001401A6973 lock cmpxchg dword ptr [rbp+30h],ecx 
00000001401A6978 jne   foo+31h (01401A6971h) 
00000001401A697A mov   dword ptr [rbp-0Ch],eax 

:これはC、I86、マイクロソフトのコンパイラVS2015、Win64の対象となっています。

幸運。

関連する問題