Share via


方法: バリアを使用して同時実行操作を同期する

以下の例では、Barrier を使用して同時実行タスクを同期する方法を示します。

使用例

以下のプログラムの目的は、ランダム化アルゴリズムを使用して単語を再シャッフルすることにより、同じフェーズで 2 つのスレッドがそれぞれソリューションの半分を探すために必要なイテレーション (またはフェーズ) の数をカウントすることです。 各スレッドで単語がシャッフルされた後、バリアのフェーズ後の操作によって、文中の単語の表示順序が正しいかどうかを確認するために 2 つの結果が比較されます。

Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Threading
Imports System.Threading.Tasks


    Class Program
        Shared words1() = New String() {"brown", "jumped", "the", "fox", "quick"}
        Shared words2() = New String() {"dog", "lazy", "the", "over"}
        Shared solution = "the quick brown fox jumped over the lazy dog."

        Shared success = False
        Shared barrier = New Barrier(2, Sub(b)
                                            Dim sb = New StringBuilder()
                                            For i As Integer = 0 To words1.Length - 1
                                                sb.Append(words1(i))
                                                sb.Append(" ")
                                            Next
                                            For i As Integer = 0 To words2.Length - 1

                                                sb.Append(words2(i))

                                                If (i < words2.Length - 1) Then
                                                    sb.Append(" ")
                                                End If
                                            Next
                                            sb.Append(".")
                                            System.Diagnostics.Trace.WriteLine(sb.ToString())

                                            Console.CursorLeft = 0
                                            Console.Write("Current phase: {0}", barrier.CurrentPhaseNumber)
                                            If (String.CompareOrdinal(solution, sb.ToString()) = 0) Then
                                                success = True
                                                Console.WriteLine()
                                                Console.WriteLine("The solution was found in {0} attempts", barrier.CurrentPhaseNumber)
                                            End If
                                        End Sub)

        Shared Sub Main()
            Dim t1 = New Thread(Sub() Solve(words1))
            Dim t2 = New Thread(Sub() Solve(words2))
            t1.Start()
            t2.Start()

            ' Keep the console window open.
            Console.ReadLine()
        End Sub

        ' Use Knuth-Fisher-Yates shuffle to randomly reorder each array.
        ' For simplicity, we require that both wordArrays be solved in the same phase.
        ' Success of right or left side only is not stored and does not count.       
        Shared Sub Solve(ByVal wordArray As String())
            While success = False
                Dim rand = New Random()
                For i As Integer = 0 To wordArray.Length - 1
                    Dim swapIndex As Integer = rand.Next(i + 1)
                    Dim temp As String = wordArray(i)
                    wordArray(i) = wordArray(swapIndex)
                    wordArray(swapIndex) = temp
                Next

                ' We need to stop here to examine results
                ' of all thread activity. This is done in the post-phase
                ' delegate that is defined in the Barrier constructor.
                barrier.SignalAndWait()
            End While
        End Sub
    End Class
//#define TRACE
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace BarrierSimple
{
    class Program
    {
        static string[] words1 = new string[] { "brown",  "jumped", "the", "fox", "quick"};
        static string[] words2 = new string[] { "dog", "lazy","the","over"};
        static string solution = "the quick brown fox jumped over the lazy dog.";

        static bool success = false;
        static Barrier barrier = new Barrier(2, (b) =>
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < words1.Length; i++)
            {
                sb.Append(words1[i]);
                sb.Append(" ");
            }
            for (int i = 0; i < words2.Length; i++)
            {
                sb.Append(words2[i]);

                if(i < words2.Length - 1)
                    sb.Append(" ");
            }
            sb.Append(".");
#if TRACE
            System.Diagnostics.Trace.WriteLine(sb.ToString());
#endif
            Console.CursorLeft = 0;
            Console.Write("Current phase: {0}", barrier.CurrentPhaseNumber);
            if (String.CompareOrdinal(solution, sb.ToString()) == 0)
            {
                success = true;
                Console.WriteLine("\r\nThe solution was found in {0} attempts", barrier.CurrentPhaseNumber);
            }
        });

        static void Main(string[] args)
        {

            Thread t1 = new Thread(() => Solve(words1));
            Thread t2 = new Thread(() => Solve(words2));
            t1.Start();
            t2.Start();

            // Keep the console window open.
            Console.ReadLine();
        }

        // Use Knuth-Fisher-Yates shuffle to randomly reorder each array.
        // For simplicity, we require that both wordArrays be solved in the same phase.
        // Success of right or left side only is not stored and does not count.       
        static void Solve(string[] wordArray)
        {            
            while(success == false)
            {
                Random random = new Random();
                for (int i = wordArray.Length - 1; i > 0; i--)
                {
                    int swapIndex = random.Next(i + 1);
                    string temp = wordArray[i];
                    wordArray[i] = wordArray[swapIndex];
                    wordArray[swapIndex] = temp;
                }

                // We need to stop here to examine results
                // of all thread activity. This is done in the post-phase
                // delegate that is defined in the Barrier constructor.
                barrier.SignalAndWait();
            }
        }
    }
}

Barrier は、すべてのタスクがバリアに到達するまで、並行操作の個々のタスクが続行されないようにするオブジェクトです。 これは、1 つの並行操作が複数のフェーズで行われ、各フェーズでタスク間の同期が必要となる場合に便利です。 この例では、操作に 2 つのフェーズがあります。 最初のフェーズでは、各タスクはバッファーの対応する領域をデータで埋めます。 各タスクは、その領域を埋め終わると、続行できる状態になったことをバリアに通知し、待機します。 すべてのタスクがバリアに通知すると、ブロックが解除され、2 番目のフェーズが開始されます。 2 番目のフェーズでは、各タスクからすべてのデータにアクセスするため、その時点までにすべてのデータが生成されている必要があります。バリアが必要になるのはこのためです。 バリアがないと、最初に完了したタスクが、他のタスクがまだ埋め終わっていないバッファーから読み取ろうとする可能性があります。 同様の方法で、任意の数のフェーズを同期できます。

参照

概念

並列プログラミングのデータ構造