Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Это System.Threading.Barrier примитив синхронизации, который позволяет нескольким потокам (как участникам) одновременно работать над алгоритмом на этапах. Каждый участник исполняет код до тех пор, пока не достигнет барьерной точки в программе. Барьер представляет конец одного этапа работы. Когда участник достигает барьера, он блокирует до тех пор, пока все участники не достигли одного и того же барьера. После того как все участники достигли барьера, можно при необходимости вызвать действие после этапа. Это послефазное действие можно использовать для выполнения действий одним потоком, когда все остальные потоки остаются заблокированными. После выполнения действия все участники разблокируются.
В следующем фрагменте кода показан базовый шаблон барьера.
// 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 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();
}
' 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 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
Полный пример см. в разделе "Практическое руководство. Синхронизация параллельных операций с барьером".
Добавление и удаление участников
При создании экземпляра Barrier укажите количество участников. Вы также можете добавлять или удалять участников динамически в любое время. Например, если один участник решает свою часть задачи, можно сохранить результат, остановить выполнение в этом потоке и вызвать Barrier.RemoveParticipant, чтобы уменьшить количество участников в барьере. При добавлении участника путем вызова Barrier.AddParticipantвозвращаемое значение указывает текущий номер этапа, который может оказаться полезным для инициализации работы нового участника.
Сломанные барьеры
Взаимоблокировки могут возникать, если один участник не достигнет границы. Чтобы избежать взаимоблокировок, используйте перегрузки метода Barrier.SignalAndWait для указания периода ожидания и маркера отмены. Эти перегрузки возвращают логическое значение, которое каждый участник может проверить перед переходом к следующему этапу.
Исключения после этапа
Если делегат после этапа создает исключение, он упаковывается в BarrierPostPhaseException объект, который затем распространяется на всех участников.
Барьер и ContinueWhenAll
Барьеры особенно полезны, если потоки выполняют несколько этапов в циклах. Если коду требуется только один или два этапа работы, рассмотрите, следует ли использовать System.Threading.Tasks.Task объекты с любым неявным соединением, в том числе:
Дополнительные сведения см. в теме Связывание задач с использованием задач-продолжений.