4

この MSDN 記事によると、各スレッドが単一のルート トランザクションに参加するプロセスをマルチスレッド化できるはずです。

その記事に基づいて、トランザクションがロールバックされることを期待するサンプルを作成しました (bool[] resultsすべてfalseforeachループ内にある必要があります)。残念ながら、これは当てはまらず、結果は予測不可能です (例を十分に実行するとbool、配列内の値の任意の組み合わせが表示されます)。

さらに、私は両方を試しましたがDependentCloneOption.BlockCommitUntilCompleteDependentCloneOption.RollbackIfNotCompleteどちらも期待どおりの結果をもたらしませんでした。

ThreadPool.QueueUserWorkItem第二に、せいぜい醜いコードだと思いますParallel.ForEach。代わりにこのようなものを使用するのを見るといいでしょう。

そして最後に、私の質問:)一体なぜこれが機能しないのですか? 私は何を間違っていますか?単一のトランザクションで複数のスレッドをラップすることはまったく不可能ですか?

namespace Playing
{
    class Program
    {
        static bool[] results = new bool[] { false, false, false };

        static void Main(string[] args)
        {
            try
            {
                using (var outer = new TransactionScope(
                    TransactionScopeOption.Required))
                {
                    for (var i = 0; i < 3; i++ )
                    {
                        ThreadPool.QueueUserWorkItem(WorkerItem,
                            new Tuple<int, object>(
                                i, Transaction.Current.DependentClone(
                                    DependentCloneOption.BlockCommitUntilComplete)));
                    }
                    outer.Complete();
                }
            }
            catch { /* Suppress exceptions */ }

            // Expect all to be false
            foreach (var r in results)
                Console.WriteLine(r);
        }

        private static void WorkerItem(object state)
        {
            var tup = (Tuple<int, object>)state;
            var i = tup.Item1;
            var dependent = (DependentTransaction)tup.Item2;

            using (var inner = new TransactionScope(dependent))
            {
                // Intentionally throw exception to force roll-back
                if (i == 2)
                    throw new Exception();

                results[i] = true;
                inner.Complete();
            }
            dependent.Complete();
        }
    }
}
4

1 に答える 1

4

true に設定された結果 [] メンバーは、魔法のように自分自身を false に戻すことはありません (悲しいことに)。それがトランザクション マネージャーの役​​割です。EnlistXXX メソッドを見て、何が関係しているかを理解してください。

基本的に、ロールバックが発生した場合は補償する必要があります。たとえば、ルート トランザクションの TransactionCompleted イベントをサブスクライブして、トランザクションがロールバックされたかどうかを確認できます。その場合は、完了した子ワーカーの以前の値を復元する必要があります。

抑制している TransactionAbortedException スローを処理するか、ワーカー レベルで処理することもできます (このページでキャッチの例を参照してください: http://msdn.microsoft.com/en-us/library/ms973865.aspx )

通常、メモリ内の「トランザクション」では、Task ライブラリを使用してワーカーに結果をまとめてもらい、親タスクの継続でそれらを「コミット」させる方がよいでしょう。トランザクションをいじるよりも簡単です。これは、メモリと他のトランザクション マネージャー (SQL Server や他のプロセスなど) との間で調整を行う場合にのみ行う必要があります。

于 2013-10-09T13:36:58.517 に答える