2017-03-10 13 views
6

実行順序を変更するコンパイラに関する質問があります。私は、マルチスレッドプログラム(C言語)のパフォーマンスを改善するために、重要なセクションをシグナリングメカニズム(厳しいセマフォ)に置き換えようとしています。揮発性またはメモリバリアとロックを使用せずに実行順序を保証する

私はここで実行の順序を保証する必要があり、これについていくつかの調査を行っています。関数内での実行順序については多くの質問がありましたが、関数内の関数についての議論はあまりありませんでした。 https://en.wikipedia.org/wiki/Sequence_pointルール#4に基づい

、以下のコードチャンクは、コンパイラを想定入力(ここで定義されたスケジュール・ポイントのルールに付着ようfunc2pがかかるため*p->afunc2前に最初に評価されなければならないが入力されることを保証するであろう)?

func1 (struct *p) { 
    p->a = x; 
    func2 (p); 
} 

func2 (struct *p) { 
    p->b = y; 
    releaseSemaphore(s); 
} 

p->bが別のスレッドは、様々な要求を処理するループ内にあり、p->bが設定されているかどうかによって、有効な要求を識別するようp->aが設定された後にのみ設定されていることが重要です。解放セマフォは、アイドル状態(セマフォ待ち状態)のタスクのみをトリガしますが、他の要求を処理中の場合はp->bをチェックし、そのスレッドがアイドル状態のときにのみ呼び出されることを保証することはできません。

+1

pは原子ではないので、*別のスレッドがさまざまな要求を処理しているときにp-> aが設定された後にのみp> bが設定され、p-> bは設定されています*データレースのように見えます。 – 2501

+0

コンパイラがC11をサポートしている場合、アトミックを使用することができます。たとえば、スレッド1はp> bでstore-releaseを行い、スレッド2はp-> bでロードを取得します。 – ninjalj

答えて

2

No.シーケンスポイントの順序がスレッドの境界を超えて遷移しません。それが、なぜ我々が最初にメモリ注文保証を必要とするのかという全体的なポイントです。

コードを実行するスレッドのシーケンスポイントの順序付けは常に保証されています(仮にif-if-rule)。任意の他のスレッドは、そのスレッドの書き込みを任意の順序で観察する可能性があります。つまり、スレッド#1が特定の順序で書き込みを実行していることを確認できたとしても、スレッド#2はそれを別の順序で観察している可能性があります。そのため、揮発性もここでは十分ではありません。

これは技術的に説明できます。キャッシュによって。スレッド#1による書き込みは、最初に書き込みバッファに移動することがあり、スレッド#2にはまだ見えません。ライトバッファがメインメモリにフラッシュされると、それらは見えるようになり、フラッシュする前にハードウェアがライトの順序を変更することができます。

プラットフォームが書き込みを並べ替えることが許可されているからといって、そのことを意味するわけではありません。これは危険な部分です。 1つのプラットフォームで完全に正常に動作するコードは、別のプラットフォームに移植されたときに青色から抜ける可能性があります。適切なメモリの順序付けを使用すると、コードはすべてで動作することが保証されます。

+1

また、「シーケンスポイント」という用語は、より現代的で正確な「順序付けられた前の」用語に賛成して非難されています。 –

+0

ありがとう、キャッシュの説明は、このポイントを置くのに役立つ多くのでした。 –

1

実装可能他の翻訳単位からの関数呼び出しに対してこれが行われない限り、順序を変更してください。

このような並べ替えは、マルチスレッドと直交します。つまり、シングルスレッドとマルチスレッドの両方のプログラムで実行されます。

関数func2のは、関数func1と同じ翻訳単位内にある場合かのように、実行を行うことができます:揮発性

func1 (struct *p) 
{ 
    func2 (p); 
    p->a = x; 
} 

使用あなたがなreorderingsを防ぎたい場合に限っ。 (これは、上記の並べ替えを防ぐために行われ、他の同期目的では行われません。これらのプリミティブは原子原型を使用する必要があります。)


(より引用:ISO/IEC 9899:201X 5.1.2.3プログラムの実行10)
あるいは、実装が実際のセマンティクスがあろうと、各変換ユニット、例えば 内の様々な最適化を実行するかもしれません 翻訳単位の境界を越えて関数呼び出しを行う場合にのみ、抽象セマンティクスに同意します。
揮発性修飾型は 実装に未知の方法で変更または他の未知の副作用を有することができる持っているオブジェクト(:ISO/IEC 9899 201X 6.7.3タイプ修飾子7から引用)

。したがって、そのようなオブジェクトに対して を参照する表現は、抽象機械の規則に従って厳密に評価されなければならない( )。さらに、すべてのシーケンスポイントにおいて、 オブジェクトに最後に格納された値は、前述の未知の要因である によって修正された場合を除き、抽象マシンによって規定された値と一致しなければならない。

+0

同じ翻訳単位内でこの並べ替えを確認していただきありがとうございます。毎日何か新しいことを学ぶ。残念私は1つの答えに私の印を与えることができます:) –

+0

@ Danzもちろんこの並べ替えは、プログラムの観察可能な振る舞いを同じに保つ必要があります。コンパイラは、メンバbのみが関数func2で変更され、メンバaはまったくアクセスされないことをコンパイラが認識するため、この場合に実行できます。そうでない場合、メンバーaも関数func2で読み取られた場合、メンバーaへの書き込みは前記関数の下に移動できません。 – 2501

関連する問題