これは、TL2 STMアルゴリズムの概要を説明し、それを実装する上でかなり読みやすいいくつかの論文へのリンクと、通常のコードをSTMコードに機械的に変換する方法へのリンクを提供する回答へのリンクです。
Stackoverflow: ソフトウェア トランザクショナル メモリをどのように実装しますか?
明らかに活発な研究分野であり、多くのアプローチがあります。特定の問題に最適な方法は、目前の問題の同時実行性と読み取り/書き込み比率によって異なります。
TL2 アルゴリズムに関して、あなたの質問:
... 同じトランザクション内で 2 つのスレッドを実行できるようにするのは無意味に思えます。それらは互いの書き込みを読み取り、トランザクション ブロック内の計算は不正な形式になります。
実行中のコードではなく、トランザクション中に表示されるデータ (読み取りセット) または更新されるデータ (書き込みセット) に関するものです。TL2 アルゴリズムを使用すると、ロックを保持せずに投機的な作業を行うことができ、コミットまで書き込みセットを各スレッドに非公開に保つことができます。コミット時に、トランザクションは書き込みロックを取得し、読み取りセットのバージョンがマスター値のバージョン (パブリックにコミットされた値) と一致することを最終バージョンでチェックしてから、更新内容をマスター値にフラッシュしてバージョンをインクリメントします。もちろん、トランザクションはコミット前に独自のプライベート更新とコミットされたマスター値を見ることができますが、異なる tx はフラッシュされていない書き込みセットをお互いに見ることはありません。他のトランザクションがその間にコミットされ、読み取りセットで見られたものからマスター バージョンを変更した場合、tx は中止されます。これにより、アプリケーション ロジックの実行中にロックを保持することなく一貫性が保たれます。上記のリンクにある論文には、より多くの詳細と最適化が記載されています。
また、2 つのスレッドが同時に同じトランザクションに入るとどうなりますか? これは一種の競合状態を引き起こしませんか?
はい、スレッドは、他のスレッドが更新する値を読み取っている場合、別の作業を行うときに TL2 と競合します。最終的な整合性チェックで中止されるため、作業が破棄される可能性があります。これが発生した場合は、最終的にコミットの成功につながる一貫した読み取りが得られるまで、何度も再試行するようにコーディングする必要があります。サーバーに多くのコアがある場合、コアをブロックする粗い粒度のロックを使用するよりも、時々コアの作業を捨てることで、より多くの総スループットが得られることが期待されます。もう 1 つの希望は、デッドロックを回避する最適なきめの細かいロック アプローチを手動で作成するよりも、STM の方がより単純であるということです。明らかに、スループットは実際のアプリケーション ロジックと衝突に依存します。
どちらも同じ共有メモリを変更しようとしているため、両方を再起動する必要があり、システムが介入して 1 つのスレッドにそれを冷却するように指示しない限り、問題は無限に続きます (ロック = のようなものです)。
あなたが言及したライブロックは、コミット時にマスター値をロックすることで回避されます。マスター値メモリ アドレスのメモリ昇順ですべてのロックを取得すると、デッドロックは発生しません。2 つのスレッドのうちの 1 つが、最初に必要なすべてのロックを取得します。もう一方はブロックします。次に、最初のスレッドが読み取りセットの整合性チェックを行い、書き込みセットをフラッシュしてマスター値をインクリメントし、ロックを解放します。2 番目のスレッドは、最終的にすべてのロックを取得し、読み取りセットの整合性チェックを行い、アプリケーション ロジックで使用したマスター値のバージョンをスレッド 1 がインクリメントしたことを確認して、トランザクションを中止します。
明らかに、このコミット時間ロック戦略はスレッドをブロックしますが、任意のアプリケーション ロジックが実行されている間はロックは保持されません。このクリティカル セクションは積極的に調整できます。これらの論文は、スレッドがロックを保持している間、スレッドを中断せずに実行することを要求するプロセッサ命令についても言及しています。