방법: 동시 작업을 배리어와 동기화

다음 예제는 Barrier와 동시 작업을 동기화하는 방법을 보여줍니다.

예시

다음 프로그램의 목적은 무작위 알고리즘을 사용하여 단어를 다시 섞어서 동일한 단계에서 두 스레드가 솔루션의 절반을 서로 찾는 데 필요한 반복(또는 단계) 수를 계산하는 것입니다. 각 스레드가 해당 단어를 섞은 후 장벽 사후 단계 작업은 두 결과를 비교하여 전체 문장이 올바른 단어 순서로 렌더링되었는지 확인합니다.

//#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",  "jumps", "the", "fox", "quick"};
        static string[] words2 = new string[] { "dog", "lazy","the","over"};
        static string solution = "the quick brown fox jumps 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();
            }
        }
    }
}
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Threading
Imports System.Threading.Tasks


Class Program
    Shared words1() = New String() {"brown", "jumps", "the", "fox", "quick"}
    Shared words2() = New String() {"dog", "lazy", "the", "over"}
    Shared solution = "the quick brown fox jumps 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

Barrier는 모든 작업이 장벽에 도달할 때까지 병렬 작업의 개별 작업이 계속되는 것을 방지하는 개체입니다. 이 개체는 병렬 작업이 단계에서 발생하는 경우에 유용하며, 각 단계에서는 작업 간 동기화가 필요합니다. 이 예제에서, 작업의 단계는 두 개입니다. 첫 번째 단계에서 각 작업은 데이터를 사용하여 버퍼의 섹션을 채웁니다. 각 작업이 해당 섹션 채우기를 완료하면 작업은 장벽에 계속할 준비가 되었음을 알리는 신호를 보낸 후 대기합니다. 모든 작업이 장벽에 신호를 보내면 장벽이 잠금 해제되고 두 번째 단계가 시작됩니다. 두 번째 단계에서는 각 작업이 이 지점까지 생성된 모든 데이터에 액세스해야 하므로 장벽이 필요합니다. 장벽이 없으면 완료할 첫 번째 작업이 다른 작업에 의해 아직 채워지지 않은 버퍼에서 읽으려고 할 수 있습니다. 이런 방식으로 개수와 관계없이 모든 단계를 동기화할 수 있습니다.

참고 항목