다음을 통해 공유


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

다음 예제에서는 Barrier를 사용하여 동시 작업을 동기화하는 방법을 보여 줍니다.

예제

다음 프로그램의 목적은 무작위 선택 알고리즘으로 단어를 뒤섞은 후 두 스레드가 각각 동일한 단계에서 해의 절반을 각각 찾아내는 데 필요한 반복(또는 단계) 횟수를 구하는 데 있습니다. 각 스레드에서 해당 단어를 뒤섞은 후 배리어 사후 단계 작업으로 두 결과를 비교하여 완전한 문장이 올바른 단어 순서대로 렌더링되었는지 확인합니다.

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는 병렬로 실행되는 작업이 모두 장벽에 도달할 때까지 개별 작업이 계속 실행되고 있지 않도록 방지하는 개체입니다. 이는 병렬 작업이 단계별로 이루어지고 각 단계에서 작업 사이에 동기화가 필요한 경우 유용합니다. 이 예제에서는 작업이 두 단계로 진행됩니다. 첫째 단계에서는 각 작업을 통해 해당 버퍼 섹션을 데이터로 채웁니다. 각 작업에서 해당 섹션을 채우고 나면 다음 단계를 계속 진행할 준비가 되었다는 신호가 장벽에 보내지고 작업은 대기 상태로 들어갑니다. 모든 작업에서 장벽에 신호를 보내고 나면 대기 상태이던 작업의 차단이 해제되고 둘째 단계가 시작됩니다. 둘째 단계에서는 각 작업을 통해 현재 시점까지 생성된 모든 데이터에 액세스해야 하므로 두 단계를 구분하는 이와 같은 장벽이 필요합니다. 장벽이 없으면 먼저 완료된 작업에서 아직 다른 작업을 통해 미처 채우지 못한 버퍼의 데이터를 읽으려고 시도할 수 있습니다. 이와 같은 방식으로 동기화할 수 있는 단계의 수에는 제한이 없습니다.

참고 항목

개념

병렬 프로그래밍을 위한 데이터 구조