方法: バリアを使用して同時実行操作を同期する
次の例は、Barrier を使用して同時実行タスクを同期する方法を示しています。
例
次のプログラムの目的は、単語を再シャッフルするためにランダム化アルゴリズムを使用して、同じフェーズで 2 つのスレッドのそれぞれのソリューションの半分を検索するのに必要な反復 (またはフェーズ) の数をカウントすることです。 各スレッドで単語をシャッフルした後、バリアのフェーズ後操作で 2 つの結果が比較され、完全な文が正しい語順でレンダリングされているかどうかが確認されます。
//#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 はオブジェクトであり、すべてのタスクがバリアに到達するまで、並列操作の個々のタスクが続行されないようにします。 これは、並列操作を段階的に行う場合、および各フェーズでタスク間の同期が必要な場合に便利です。 この例では、2 つの操作フェーズがあります。 最初のフェーズでは、各タスクでバッファーのセクションにデータが読み込まれます。 各タスクでそのセクションへの読み込みが終了すると、タスクは続行する準備ができていることをバリアに通知してから、待機します。 すべてのタスクがバリアに通知した時点で、ブロックが解除され、2 番目のフェーズが開始されます。 2 番目のフェーズでは、各タスクがこれまでに生成されたすべてのデータにアクセスできる必要があるため、バリアが必要です。 バリアがないと、実行する最初のタスクで、他のタスクによってまだデータが読み込まれていないバッファーからの読み取りが試行される場合があります。 このように任意の数のフェーズを同期することができます。
関連項目
.NET