Барьер (.NET Framework)
Барьер — это определяемый пользователем примитив синхронизации, разрешающий нескольким потокам (называемым участниками) выполнять алгоритм параллельно и поэтапно. Каждый участник выполняется, пока его код не достигнет точки барьера. Барьер означает окончание одного этапа работы. Когда участник достигает барьера, его выполнение блокируется, пока все участники не достигнут этого же барьера. Когда все участники достигнут барьера, при необходимости можно вызвать действие следующего этапа. Это действие следующего этапа может использоваться для выполнения действий одним потоком, пока все остальные потоки все еще остаются блокированными. После выполнения этого действия блокировка всех участников снимается.
В следующем фрагменте кода показан базовый шаблон барьера.
' Create the Barrier object, and supply a post-phase delegate
' to be invoked at the end of each phase.
Dim barrier = New Barrier(2, Sub(bar)
' Examine results from all threads, determine
' whether to continue, create inputs for next phase, etc.
If (someCondition) Then
success = True
End If
End Sub)
' Define the work that each thread will perform. (Threads do not
' have to all execute the same method.)
Sub CrunchNumbers(ByVal partitionNum As Integer)
' Up to System.Int64.MaxValue phases are supported. We assume
' in this code that the problem will be solved before that.
While (success = False)
' Begin phase:
' Process data here on each thread, and optionally
' store results, for example:
results(partitionNum) = ProcessData(myData(partitionNum))
' End phase:
' After all threads arrive,post-phase delegate
' is invoked, then threads are unblocked. Overloads
' accept a timeout value and/or CancellationToken.
barrier.SignalAndWait()
End While
End Sub
' Perform n tasks to run in in parallel. For simplicity
' all threads execute the same method in this example.
Shared Sub Main()
Dim app = New BarrierDemo()
Dim t1 = New Thread(Sub() app.CrunchNumbers(0))
Dim t2 = New Thread(Sub() app.CrunchNumbers(1))
t1.Start()
t2.Start()
End Sub
// Create the Barrier object, and supply a post-phase delegate
// to be invoked at the end of each phase.
Barrier barrier = new Barrier(2, (bar) =>
{
// Examine results from all threads, determine
// whether to continue, create inputs for next phase, etc.
if (someCondition)
success = true;
});
// Define the work that each thread will perform. (Threads do not
// have to all execute the same method.)
void CrunchNumbers(int partitionNum)
{
// Up to System.Int64.MaxValue phases are supported. We assume
// in this code that the problem will be solved before that.
while (success == false)
{
// Begin phase:
// Process data here on each thread, and optionally
// store results, for example:
results[partitionNum] = ProcessData(data[partitionNum]);
// End phase:
// After all threads arrive,post-phase delegate
// is invoked, then threads are unblocked. Overloads
// accept a timeout value and/or CancellationToken.
barrier.SignalAndWait();
}
}
// Perform n tasks to run in in parallel. For simplicity
// all threads execute the same method in this example.
static void Main()
{
var app = new BarrierDemo();
Thread t1 = new Thread(() => app.CrunchNumbers(0));
Thread t2 = new Thread(() => app.CrunchNumbers(1));
t1.Start();
t2.Start();
}
Полный пример см. в разделе Практическое руководство. Синхронизация параллельных операций с барьером.
Добавление и удаление участников
При создании объекта Barrier задайте число участников. Добавлять и удалять участников также можно динамически, в любое время. Например, если один участник решил свою часть проблемы, можно сохранить результат, остановить выполнение этого потока и вызвать метод RemoveParticipant, чтобы уменьшить число участников в барьере. При добавлении участника с помощью вызова метода AddParticipant возвращенное значение задает номер текущего этапа, которое может быть полезно для инициализации действий нового участника.
Разрушенные барьеры
Если одному из участников не удалось достигнуть барьера, могут возникнуть взаимные блокировки. Во избежание взаимных блокировок используйте перегруженные версии метода SignalAndWait, чтобы задать время ожидания и токен отмены. Эти перегруженные версии возвращают логическое значение, которое каждый участник может проверить перед переходом к следующему этапу.
Исключения следующих этапов
Если делегат следующего этапа создает исключение, оно заключается в оболочку объекта BarrierPostPhaseException, который затем передается всем участникам.
Сравнение барьера и ContinueWhenAll
Барьеры особенно полезны, когда потоки выполняют несколько этапов циклически. Если код требует выполнения только в один-два этапа, рассмотрите возможность использования объектов System.Threading.Tasks.Task с любым видом неявного объединения, в том числе:
Дополнительные сведения см. в разделе Практическое руководство. Сцепление нескольких задач с помощью продолжений.
См. также
Задачи
Практическое руководство. Синхронизация параллельных операций с барьером