Bagikan melalui


Penghalang

System.Threading.Barrier adalah primitif sinkronisasi yang memungkinkan beberapa utas (dikenal sebagai peserta) untuk bekerja secara bersamaan pada algoritma secara bertahap. Setiap peserta dijalankan hingga mencapai titik penghalang dalam kode tersebut. Penghalang mewakili akhir dari satu fase pekerjaan. Ketika satu peserta mencapai penghalang, ia akan memblokir hingga semua peserta mencapai penghalang yang sama. Setelah semua peserta mencapai penghalang, Anda dapat memanggil tindakan pasca-fase secara opsional. Tindakan pasca-fase ini dapat digunakan untuk melakukan tindakan oleh satu utas di saat semua utas lainnya masih diblokir. Setelah tindakan dijalankan, semua peserta tidak diblokir.

Cuplikan kode berikut menunjukkan pola penghalang dasar.


// 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

Untuk contoh lengkapnya, lihat Panduan: menyinkronkan operasi bersamaan dengan suatu Penghalang.

Menambahkan dan menghapus peserta

Saat Anda membuat Barrier instans, tentukan jumlah peserta. Anda juga dapat menambahkan atau menghapus peserta secara dinamis kapan saja. Sebagai contoh, jika satu peserta memecahkan bagian dari masalahnya, Anda dapat menyimpan hasilnya, menghentikan eksekusi pada utas tersebut, dan memanggil Barrier.RemoveParticipant untuk mengurangi jumlah peserta pada penghalang. Saat Anda menambahkan peserta dengan memanggil Barrier.AddParticipant, nilai pengembalian menentukan nomor fase saat ini, yang mungkin berguna untuk menginisialisasi pekerjaan peserta baru.

Penghalang yang rusak

Kebuntuan dapat terjadi jika satu peserta gagal mencapai penghalang. Untuk menghindari kebuntuan ini, gunakan kelebihan beban dari metode Barrier.SignalAndWait untuk menentukan periode waktu habis dan token pembatalan. Kelebihan beban ini mengembalikan nilai Boolean yang dapat diperiksa setiap peserta sebelum berlanjut ke fase berikutnya.

Pengecualian pasca-fase

Jika delegasi pasca-fase memberikan pengecualian, maka itu akan dibungkus dalam BarrierPostPhaseException objek yang kemudian disebarluaskan ke semua peserta.

Penghalang versus LanjutkanKetikaSemua

Penghalang sangat berguna ketika utas melakukan beberapa fase dalam perulangan. Jika kode Anda hanya memerlukan satu atau dua fase pekerjaan, pertimbangkan apakah akan menggunakan System.Threading.Tasks.Task objek dengan jenis gabungan implisit, termasuk:

Untuk informasi selengkapnya, lihat Merangkai Tugas dengan Menggunakan Tugas Kelanjutan.

Lihat juga