2016-03-03 28 views
5

私のコンパイラはまだC++ 11とstd :: atomicをサポートしていないので、ldrex-strexペアを使用して手動で実装する必要があります。ARM Cortex M3のint64_tア​​トミック

私の質問は:ldrexとstrexを使って '原子的に'読んだら変更してint64_tを書き込む正しい方法は何ですか?このような

簡単な解決策は、(STREXWの1が1つのすべての時間を返します)動作していないよう:

volatile int64_t value; 
int64_t temp; 

do 
{ 
    int32_t low = __LDREXW((uint32_t *)&value); 
    int32_t high = __LDREXW(((uint32_t *)&value)+1); 

    temp = (int64_t)low | ((int64_t)high<<32); 
    temp++;  

} while(__STREXW(temp, (uint32_t *)&value) | __STREXW(temp>>32, ((uint32_t *)&value)+1)); 

私は別のアドレスを指しているいくつかの連続LDREXやSTREXの指示については何も見つけることができませんでしたマニュアルはそれが許されるべきだと私には思われました。

そうしないと、複数のスレッドがいくつかのシナリオで2つの異なる原子変数を変更できなくなります。

+1

はGCCですか? GCCの組み込みアトミックを考えてみましょうか? – user3528438

+0

GCC for ARMはstd :: atomicをサポートしました。いいえ、それはGCCではなく、Keil armccです。 – Amomum

+0

参照:[ARM AN321 - Cortex-Mメモリバリア](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0321a/BIHEADII.html)。原子は少しオーバーロードされた単語です。宇宙では物事が原子的に起こることはありません。それらは原子対電子工学のセットです。メインライン/割り込み、SMP、バス上のデバイスなど何が問題ですか?あなたはそれをよりよく説明しなければなりません。 –

答えて

4

排他的な方法ではネストできないため、これはうまくいかないでしょう。インプリメンテーションに関しては、Cortex-M3ローカル排他モニタはアドレスthe exclusive reservation granule is the entire address spaceを追跡していないので、各ワードを別々にトラッキングするという前提はすでに無効です。アーキテクチャは、すでに明示的にバックツーバックstrex除外するしかし、あなたも、任意の実装の詳細を検討する必要はありません。(一般的におよびARMv7-M)のCortex-M3ので

If two STREX instructions are executed without an intervening LDREX the second STREX returns a status value of 1. This means that:

  • Every STREX must have a preceding LDREX associated with it in a given thread of execution.
  • It is not necessary for every LDREX to have a subsequent STREX .

」をdoesnのARMv7-Aのようにldrexdがある場合は、変数へのすべてのアクセスを制御するために別個のロックを使用するか、読み取り - 変更 - 書き込みの周りの割り込みを無効にする必要があります。おそらく同じコア上の他のスレッドに関してアトミック性を達成するだけなので、最初は原子64ビット型を必要としないように再設計するほうが本当に良いでしょう。 DMAコントローラのような外部エージェントの視点から見たビット・オペレーション・アトミック

+0

私はそれを恐れていました。だから私が今それを手に入れたら、_any_ ldrexは_every other_ ldrexのための排他的なモニタをリセットするでしょうか? – Amomum

+0

ありがとう、今私はそれを得る! – Amomum

+0

@Amomumそれを見ると、v7-Mにはローカル/グローバルモニタの区別さえありません。それは、v7-Aローカルモニタ状態マシンのトリムダウンバージョンのように読まれます。実際には、ハードウェアはおそらくアドレスのトラッキングを気にすることなく、メモリアクセスの排他的な状態をクリアしていると思います。 – Notlikethat

1

私はgccの動作を見て、同じ命令シーケンスを使用します。でも-mcpu=cortex-m3で、is_lock_free()がtrueを返すとstd::atomic<int64_t>を実装する

のgcc 4.8.2 主張残念ながら、実際には機能しません。を使用しようとするヘルパー関数の実装がないため、リンクされていないコードや動作しないコードを作成します。 (お試しいただきありがとうございます@Notlikethat)

Here's the test code I tried。そのリンクが死んでいる場合、この回答の古いバージョンを参照してください。この考え方は、gcc という便利なコードを作成する関連するケースで誰にでも役立つ場合に備えて、この回答を残しておきます。

+0

私はあなたがgcc 5.2.1でarmについて示唆したことを試してみました。リンカのエラーは "e:\ gcc-arm-none-eabi-5_2-2015q4-20151219-win32 \ arm-none-eabi \ include \ C++ \ 5.2です。 1 \ bits/atomic_base.h:514:std :: atomicを作成するときの '__atomic_fetch_add_8 'への未定義参照; std :: atomic は期待どおりに機能しました。スジは通ってるようだ。 – Amomum

+0

@Amomum: 'libgcc.a'のヘルパー機能が必要なときにgccのインストールは正常に動作しますか?それはgccのバグか誤ってインストールされたコンパイラの問題です。 64ビット除算は、同様のヘルパー関数を呼び出す可能性があります。 uint64_tの –

+0

区分は、期待通りに__aeabi_uldivmodを呼び出します。私はそれがバグだとは思わない、おそらく本当に原子uint64_tを実装する方法がないのだろうか?例えば、uint8_tを持たないアーキテクチャー(CHAR_BITSが8より大きい場合)は完全に正常です。だから私は__atomic_fetch_add_8を持たないことは大きな問題だとは思わない。 – Amomum

関連する問題