タグ付けされた質問 「concurrency」

コンピュータサイエンスでは、同時実行性は複数の計算を重複する期間で実行できるシステムの特性です。計算は、同じチップの複数のコアで実行されたり、同じプロセッサでプリエンプティブに時分割されたスレッドで実行されたり、物理的に分離されたプロセッサで実行されたりします。


1
Javaで使用されるメモリフェンスとは何ですか?
バージョン9でJava SEに追加された新しいクラスSubmissionPublisher(Java SE 10のソースコード、OpenJDK | docs)がどのように実装されているかを理解しようとしているVarHandleときに、以前は知らなかったいくつかのAPI呼び出しに遭遇しました。 fullFence、acquireFence、releaseFence、loadLoadFenceとstoreStoreFence。 特にメモリバリア/フェンスの概念に関していくつかの調査を行った後(以前に聞いたことがありますが、使用していなかったため、セマンティクスにはまったく不慣れでした)、それらの目的について基本的な理解ができたと思います。それにもかかわらず、私の質問は誤解から生じる可能性があるため、私はそもそもそれが正しく行われたことを確認したいと思います。 メモリバリアは、読み取りおよび書き込み操作に関する制約を並べ替えています。 メモリバリアは、読み取りまたは書き込み、あるいはその両方に制約を設定するかどうかに応じて、単方向および双方向のメモリバリアという2つの主要なカテゴリに分類できます。 C ++はさまざまなメモリバリアをサポートしていますが、これらはが提供するバリアとは一致しませんVarHandle。ただし、で利用可能なメモリバリアの一部は、対応するC ++メモリバリアと互換性のある順序付け効果をVarHandle提供します。 #fullFence と互換性があります atomic_thread_fence(memory_order_seq_cst) #acquireFence と互換性があります atomic_thread_fence(memory_order_acquire) #releaseFence と互換性があります atomic_thread_fence(memory_order_release) #loadLoadFenceそして、#storeStoreFence互換性のあるC ++カウンターパートを持っていません 詳細に関してはセマンティクスが明らかに異なるため、ここでは互換性という言葉は本当に重要なようです。たとえば、すべてのC ++バリアは双方向ですが、Javaのバリアはそうではありません(必須)。 ほとんどのメモリバリアにも同期効果があります。これらは特に、使用されているバリアタイプと、他のスレッドで以前に実行されたバリア命令に依存します。バリア命令が持つ完全な影響はハードウェア固有なので、高レベル(C ++)のバリアを使用します。たとえば、C ++では、バリア解放命令の前に行われた変更は、バリア取得命令を実行するスレッドに表示されます。 私の仮定は正しいですか?もしそうなら、私の結果の質問は: で使用可能なメモリバリアはVarHandle、何らかの種類のメモリ同期を引き起こしますか? それらがメモリ同期を引き起こすかどうかに関係なく、Javaで何を並べ替える制約が役立つのでしょうか?Javaメモリモデルは、揮発性フィールド、ロック、またはVarHandle操作など#compareAndSetが関係する場合の順序付けに関して、すでにいくつかの非常に強力な保証を提供しています。 例を探している場合:前述BufferedSubscriptionのSubmissionPublisher(上記のリンクされたソース)の内部クラスは、1079行に完全なフェンスを設定しました(関数growAndAdd;リンクされたWebサイトはフラグメント識別子をサポートしていないため、CTRL + Fを使用するだけです) )。しかし、それが何のためにあるのか私には分かりません。

2
割り当てられたタスクの1つが何らかの理由で失敗すると、Javaはexecutorサービスを停止します
いくつかのタスクを同時に、1秒の間隔で1分間実行するある種のサービスが必要です。 タスクの1つが失敗した場合、サービスとそれとともに実行されたすべてのタスクを何らかの問題が発生したことを示すインジケーターで停止します。それ以外の場合は、1分後にすべてがうまくいった場合、サービスはすべて正常に終了したことを示すインジケーターで停止します。 たとえば、私は2つの機能があります: Runnable task1 = ()->{ int num = Math.rand(1,100); if (num < 5){ throw new Exception("something went wrong with this task,terminate"); } } Runnable task2 = ()->{ int num = Math.rand(1,100) return num < 50; } ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2); task1schedule = scheduledExecutorService.scheduleAtFixedRate(task1, 1, 60, TimeUnit.SECONDS); task2schedule = …

2
Kotlinコルーチンは「前に起こる」保証をしますか?
Kotlinコルーチンは「前に起こる」保証を提供しますか? たとえばmutableVar、この場合、他のスレッドへの(潜在的に)書き込みとその後の読み取りの間に「前に起こる」保証があります。 suspend fun doSomething() { var mutableVar = 0 withContext(Dispatchers.IO) { mutableVar = 1 } System.out.println("value: $mutableVar") } 編集: たぶん、追加の例は、(変更可能性を除いて)Kotlinっぽいので、問題をより明確にするでしょう。このコードはスレッドセーフですか? suspend fun doSomething() { var data = withContext(Dispatchers.IO) { Data(1) } System.out.println("value: ${data.data}") } private data class Data(var data: Int)

1
Haskellでの並列「any」または「all」
私が何度も遭遇したパターンは、値のリストをテストすることで、値のリストをチェックし、要素の一部またはすべてが渡されたかどうかを確認する必要があるパターンです。典型的な解決策は、単に便利なビルトインを使用することであるallとany。 問題は、これらが連続して評価されることです。多くの場合、いずれかのスレッドがの「False」または「True」を見つけると、プロセスの完了と並行して評価する方がはるかに速くなります。プロセス間通信が必要であり、これを実装するのに十分なControl.Concurrentのどこにもまだ理解していないため、Control.Parallelを使用して短絡動作を実装できないと確信しています。allany これは数学ではかなり一般的なパターンです(例:Miller-Rabin Primality)ので、誰かがおそらくすでにこの問題の解決策を考えているように思いますが、明らかな理由により、「並列または/および/すべて/リスト上のすべて」をグーグル検索しますhaskell」は、関連する結果を返しません。

2
プログラマーレベルのC ++ std :: atomicでは何が保証されますか?
私はに関するいくつかの記事、講演、stackoverflowの質問を聞いて読みましstd::atomicたが、私はそれをよく理解していることを確認したいと思います。MESI(または派生した)キャッシュコヒーレンシプロトコル、ストアバッファー、キューの無効化などで遅延が発生する可能性があるため、キャッシュライン書き込みの可視性とまだ少し混乱しています。 私はx86がより強力なメモリモデルを持っていることを読みました。キャッシュの無効化が遅れると、x86は開始された操作を元に戻すことができます。しかし、私は今、プラットフォームに関係なく、C ++プログラマーとして何を想定すべきかについてのみ興味があります。 [T1:スレッド1 T2:スレッド2 V1:共有アトミック変数] std :: atomicは、 (1)変数でデータ競合は発生しません(キャッシュラインへの排他的アクセスのおかげ)。 (2)使用するmemory_orderに応じて、(バリアを使用して)順次整合性が発生することが保証されます(バリアの前、バリアの後、またはその両方)。 (3)T1のアトミック書き込み(V1)の後、T2のアトミックRMW(V1)はコヒーレントになります(そのキャッシュラインはT1に書き込まれた値で更新されます)。 しかし、キャッシュコヒーレンシープライマーの言及として、 これらすべての意味は、デフォルトで、ロードが古いデータをフェッチできることです(対応する無効化リクエストが無効化キューに置かれていた場合)。 それで、次は正しいですか? (4)std::atomicT2がT1のアトミックwrite(V)の後にアトミックread(V)の「古い」値を読み取らないことを保証しません。 (4)が正しいかどうかの質問:T1のアトミック書き込みが遅延に関係なくキャッシュラインを無効にする場合、アトミックRMW操作がアトミック読み取りではなく無効化が有効になるのをT2が待機しているのはなぜですか? (4)が間違っている場合の質問:スレッドは実行時に「古くなった」値を読み、「それが見える」のはいつですか? 回答ありがとうございます アップデート1 だから私はそのとき(3)について間違っていたようです。次のインターリーブを想像してください。最初のV1 = 0の場合: T1: W(1) T2: R(0) M(++) W(1) この場合、T2のRMWはW(1)の後に完全に発生することが保証されていますが、それでも「古い」値を読み取ることができます(私は間違っていました)。これによると、atomicは完全なキャッシュコヒーレンシを保証せず、順次一貫性のみを保証します。 アップデート2 (5)この例を想像してみてください(x = y = 0でアトミックです): T1: x = 1; T2: y = 1; T3: if (x==1 && y==0) print("msg"); …

1
他のスレッドでそのconcurrent_vectorを反復しながら、concurrency :: concurrent_vector :: push_backを呼び出すことは、同時実行安全ですか?
push_back、begin、endはhttps://docs.microsoft.com/en-us/cpp/parallel/concrt/reference/concurrent-vector-class?view=vs-2019#push_backでコンカレントセーフとして説明されてい ます ただし、以下のコードはアサートしています。要素が追加されたが、まだ初期化されていないためと考えられます。 struct MyData { explicit MyData() { memset(arr, 0xA5, sizeof arr); } std::uint8_t arr[1024]; }; struct MyVec { concurrency::concurrent_vector<MyData> v; }; auto vector_pushback(MyVec &vec) -> void { vec.v.push_back(MyData{}); } auto vector_loop(MyVec &vec) -> void { MyData myData; for (auto it = vec.v.begin(); it != vec.v.end(); ++it) { auto …

1
Haskellの計算負荷の高いスレッドが他のすべてのスレッドをブロックする
メインスレッドが計算のために新しいスレッドをフォークし、一定の期間終了するのを待つプログラムを作成したいと思います。子スレッドが所定の時間内に完了しない場合、タイムアウトして強制終了されます。これには次のコードがあります。 import Control.Concurrent fibs :: Int -> Int fibs 0 = 0 fibs 1 = 1 fibs n = fibs (n-1) + fibs (n-2) main = do mvar <- newEmptyMVar tid <- forkIO $ do threadDelay (1 * 1000 * 1000) putMVar mvar Nothing tid' <- forkIO $ do if …

4
揮発性読み取りを取り除くためにJavaでメモリバリアをエミュレートする
同時にアクセスされるフィールドがあり、何度も読み取られ、めったに書き込まれないと仮定します。 public Object myRef = new Object(); スレッドT1がmyRefを1分に1回別の値に設定し、他のN個のスレッドがmyRefを数十億回連続して同時に読み取るとします。myRefが最終的にすべてのスレッドに表示されることだけが必要です。 簡単な解決策は、AtomicReferenceまたは単にvolatileを次のように使用することです。 public volatile Object myRef = new Object(); ただし、afaikの揮発性読み取りではパフォーマンスコストが発生します。非常に小さいことはわかっていますが、これは実際に必要なものというよりは、私が不思議に思っているようなものです。したがって、パフォーマンスに関係なく、これは純粋に理論的な質問であると想定しましょう。 つまり、質問は次のようになります。書き込みサイトで何かを行うことによって、書き込みがほとんどない参照の揮発性読み取りを安全にバイパスする方法はありますか? いくつか読んだ後、メモリの壁が私が必要とするものであるように見える。したがって、このような構成が存在する場合、私の問題は解決されます。 書く バリアを呼び出す(同期) すべてが同期され、すべてのスレッドに新しい値が表示されます。(読み取りサイトでの永続的なコストがないと、キャッシュが同期されるため、古くなったり、一時的なコストが発生する可能性がありますが、その後は通常のフィールドに戻り、次の書き込みまで続きます)。 そのような構造はJava、または一般にありますか?この時点で私は仕方がありませんが、このようなものが存在する場合、それを維持するはるかに賢い人々によってすでにアトミックパッケージに組み込まれていると思います。(不定期に頻繁に読み取りと書き込みを行う必要はなかったのではないでしょうか?)それで、私の考えに何か問題があり、そのような構成はまったく不可能ですか? いくつかのコードサンプルが同様の目的で「揮発性」を使用し、それが契約前に発生することを利用するのを見てきました。別の同期フィールドがあります。例: public Object myRef = new Object(); public volatile int sync = 0; そしてスレッド/サイトを書く時: myRef = new Object(); sync += 1 //volatile write to emulate barrier これが機能するかどうかはわかりませんが、x86アーキテクチャでのみ機能すると主張する人もいます。JMSの関連セクションを読んだ後、その揮発性書き込みがmyRefの新しい値を確認する必要があるスレッドからの揮発性読み取りと結合されている場合にのみ、動作することが保証されていると思います。(したがって、揮発性の読み取りを取り除きません)。 …
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.