web-dev-qa-db-ja.com

Javaまたはその他のプログラミング言語での構成可能な同時実行性

concurrencyの研究論文を読んでいるときに Software and the Concurrency Revolutionhtml version )。私は次の行に出くわしました:

残念ながら、ロックは機能しますが、現代のソフトウェア開発にとって深刻な問題を引き起こしています。ロックの基本的な問題は、ロックが構成可能ではないことです。ロックベースの正しいコードを2つ取り、それらを組み合わせて、結果がまだ正しいことを知ることはできません。現代のソフトウェア開発は、ライブラリをより大きなプログラムに構成する能力に依存しているため、ロックベースのコンポーネントを実装を検討せずに構築することができないのは深刻な問題です。

  1. Javaがどのようにして構成可能な同時実行性を保証するか、あるいはこのシナリオを生成する方法があるかさえ考えていました。

  2. また、1つ以上のライブラリのデータをどのように同期させることができますか?プログラマは自分のプログラムからそれを実行できますか、それとも同期をとるのはライブラリ次第です。

  3. そうでない場合Java次に、ロックベースの同時実行性を使用して構成可能な同時実行性を保証する他の言語はありますか?

以下も同じ論文から引用したものです。

同期メソッドには少なくとも3つの大きな問題があります。 1つ目は、他のオブジェクト(Javaのベクターや.NETのSyncHashTableなど)で仮想関数を呼び出すメソッドを持つ型には適していません。ロックを保持しながらサードパーティのコードを呼び出すことで可能性が広がるためです。デッドロック。第2に、同期されたメソッドは、すべてのオブジェクトインスタンス(通常はスレッド間で共有されていないもの)でもロックを取得および解放することにより、過度のロックを実行する可能性があります。第3に、同期されたメソッドは、プログラムがオブジェクトまたは異なるオブジェクトに対して複数のメソッドを呼び出すときに原子性を維持しないため、あまりにも少ないロックを実行できます。後者の簡単な例として、銀行振込を考えてみましょう。account1.Credit(amount); account2.Debit(amount)...

注:論文は2005年9月に発行されました

8
user183296

Java言語ではありません。ロック(ミューテックス)の性質です。

正しいことを保証しながら並行性を改善するためのより良い方法があり、言語に依存しない方法があります。

  1. 不変オブジェクトを使用して、ロックを必要としないようにします。
  2. Promiseと継続渡しスタイルを使用します。
  3. ロックフリーのデータ構造を使用します。
  4. ソフトウェアトランザクションメモリを使用して状態を安全に共有する。

これらの手法はすべて、ロックを使用せずに並行性を向上させることができます。それらのどれもJava言語に特に依存していません。

7
Robert Harvey

Java構成可能な同時実行性を保証する方法、またはこのシナリオを作成する方法さえあるかと思っていました。

記事で述べているように、仮想メソッド(または関数をパラメーターとして渡すなどの他の同様のメカニズム)と共にロックを使用する場合、構成可能性を保証することはできません。コードの一部が別のコードからの仮想メソッドにアクセスでき、両方ともロックを使用する可能性がある場合、安全に(つまり、デッドロックのリスクなしに)2つのコードを構成するには、ソースコードを検査する必要があります。両方とも。

また、1つ以上のライブラリのデータをどのように同期させることができますか?プログラマは自分のプログラムからそれを実行できますか、それとも同期をとるのはライブラリ次第です。

一般に、ライブラリを使用して同期を行うのはプログラマーの責任です。このようにして、プログラマーはすべてのロックがどこにあるかを知っており、デッドロックしないことを確認できます。

そうでない場合Java次に、ロックベースの同時実行性を使用して構成可能な同時実行性を保証する他の言語はありますか?

繰り返しますが、この記事の要点は、これは不可能であることです。

3
svick

低レベルのロックメカニズムは本質的に構成できません。これは主に、ロックが世界の下に達して、命令を実行するマシンに影響を与えるためです。

後続のJavaライブラリは、正しいマルチスレッド操作を保証するために、より高いレベルのメカニズムを追加しています。それらは、lock()およびvolatileの使用を特定のウェルに制限することによってこれを行います-既知の制御可能な状況。たとえば、並行キューの実装には非常に局所的な動作があり、前の状態と後の状態について推論することができます。より高いレベルのメカニズムを使用すると、仕様またはコードの読み取りが少なくて済みます。これは大きな問題ですが、サブシステムのロックモデルと、サブシステムが互いにどのように相互作用するかを理解する必要があります。また、Javaの変更によるJava 5はほとんど言語に関係なくライブラリにのみ関係しています。

ロックメカニズムの主な問題は、状態に影響し、時間領域で動作することです。人間もコンピュータも、状態や時間について十分な根拠はありません。コンピューターの科学者がモナドを思いついたのは、言語の構成可能性に関して最初に思い浮かんだのは、価値と構造を推論する能力です。

一番近いのは Communicating Sequential Processes です。これには、メールボックスやメッセージパッシングなどの高レベルのメカニズムが必要です。私の控えめな意見では、CSPは依然として大規模なシステム(コンポーザブルソフトウェアの最終的なターゲット)や時間ベースの推論を適切に処理していません。

1
BobDalgleish

デッドロックを構築するためにあらゆる有用な同期メカニズムを使用できると評判の研究者が言ったと聞いたことがあります。トランザクションメモリ(ハードウェアまたはソフトウェア)に違いはありません。たとえば、スレッドバリアを作成するこのアプローチを考えてみます。

transaction {
    counter++;
}

while (true) {
    transaction {
        if (counter == num_threads)
            break;
    }
}

(注:この例は、PACT 2009のYannis Smaragdakisによる論文から引用されています)

これが多数のスレッドを同期するための良い方法ではないという事実を無視すると、それは正しいようです。しかし、それは構成可能ではありません。ロジックを2つのトランザクションに入れる決定は不可欠です。これを別のトランザクションから呼び出し、すべてが1つのトランザクションにフラット化される場合、おそらく完了しません。

同じことがメッセージパッシングチャネルにも当てはまります。通信サイクルがデッドロックを引き起こす可能性があります。 C++アトミックとのアドホック同期は、デッドロックを引き起こす可能性があります。 RCU、シーケンスロック、リーダー/ライターロック、条件変数、およびセマフォをすべて使用して、デッドロックを作成できます。

トランザクションやチャネル(またはロックやRCU)が悪いと言っているのではありません。むしろ、それはいくつかのことは単に不可能に思われると言うことです。スケーラブルで構成可能な、病理のない同時実行制御メカニズムはおそらく不可能です。

トラブルを回避する最善の方法は、銀の弾丸メカニズムを探すことではなく、適切なパターンを厳密に使用することです。並列計算の世界では、Arch Robison、James Reinders、Michael McCoolによるStructured Parallel Programming:Patterns for Efficient Computationが出発点として適しています。並行プログラミングの場合、いくつかの良いパターンがあります(@gardenheadのコメントを参照)が、C++およびJavaプログラマーはそれらを使用する可能性は低いです。より多くの人々が正しい方法を使い始めることができる1つのパターンは、マルチプロデューサー、マルチコンシューマーキューを使用するプログラムでのアドホック同期。TMはロックよりも優れており、抽象化のレベルが上がるため、プログラマーはアトミックにする必要があるものに集中できます。ではありません原子性を確保するための巧妙なロックプロトコルを実装する方法。うまくいけば、ハードウェアTMが向上し、言語がより多くのTMサポートを追加すると、TMが一般的なケースでロックに取って代わるようになります。

1
Mike Spear