Linux membarrier() dapat memindahkan sebagian biaya sinkronisasi dari jalur yang sangat sering dieksekusi ke jalur koordinasi yang lebih jarang. Dengan MEMBARRIER_CMD_PRIVATE_EXPEDITED, satu thread meminta kernel membentuk titik memory ordering bagi thread yang sedang berjalan dalam proses yang sama. Biaya system call dibayar saat koordinasi diperlukan, bukan dengan menempatkan hardware memory barrier pada setiap eksekusi fast path.
Mekanisme ini lebih sempit daripada rendezvous thread umum. membarrier() tidak menjalankan callback aplikasi pada sibling thread, tidak menunggu acknowledgement pada level aplikasi, dan tidak membuat data race biasa menjadi sinkronisasi yang valid. Kontraknya berfokus pada pengurutan akses memori userspace di sekitar barrier.
Private expedited menargetkan satu proses
MEMBARRIER_CMD_PRIVATE_EXPEDITED berlaku pada sibling thread yang sedang berjalan milik thread pemanggil. Ketika pemanggilan berhasil kembali, sibling yang sedang berjalan telah melewati state tempat akses memori userspace mereka terurut terhadap operasi membarrier(). Thread yang tidak sedang berjalan sudah dianggap memenuhi state yang diperlukan.
Scope tersebut penting. Perintah private tidak menerapkan barrier yang sama pada proses lain. Linux juga memiliki bentuk global, tetapi target dan aturan registrasinya berbeda.
Proses harus melakukan registrasi sebelum menjalankan operasi private expedited:
syscall(SYS_membarrier,
MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED,
0, 0);
syscall(SYS_membarrier,
MEMBARRIER_CMD_PRIVATE_EXPEDITED,
0, 0);glibc tidak menyediakan wrapper untuk membarrier(), sehingga aplikasi memanggilnya melalui syscall().
Registrasi bukan sekadar bookkeeping opsional. Private expedited tanpa registrasi yang diperlukan gagal dengan EPERM. Registrasi memberi kernel kesempatan menyiapkan proses untuk mekanisme expedited sebelum permintaan barrier yang sensitif terhadap latency dijalankan.
Dukungan command diperiksa saat inisialisasi
MEMBARRIER_CMD_QUERY mengembalikan bit mask command yang didukung kernel aktif. Software dapat memeriksa bit registrasi dan eksekusi sebelum memilih strategi sinkronisasi ini.
int mask = syscall(SYS_membarrier, MEMBARRIER_CMD_QUERY, 0, 0);
if ((mask & MEMBARRIER_CMD_PRIVATE_EXPEDITED) &&
(mask & MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED)) {
/* Mode ini tersedia. */
}Batas query ini relevan karena membarrier() spesifik untuk Linux dan ketersediaan command bergantung pada kemampuan kernel serta arsitektur. Software yang bergantung pada mode expedited sebaiknya menetapkan dukungan saat inisialisasi, bukan menganggap versi kernel saja menjamin seluruh command tersedia.
Untuk pemanggilan dengan flags bernilai nol, hasil yang didokumentasikan bagi command tertentu tetap sama hingga reboot. Karena itu, capability check dan registrasi satu kali cocok ditempatkan pada startup proses.
Expedited memindahkan biaya ke sisi koordinasi
Desain sinkronisasi konvensional dapat menempatkan hardware memory barrier pada jalur yang dieksekusi banyak thread. Jika jalur tersebut sangat sering dipakai, biaya kecil per operasi dapat melampaui biaya event koordinasi yang jauh lebih jarang.
membarrier() mendukung pembagian biaya sebaliknya. Fast path dapat memakai compiler barrier ketika algoritmanya mengizinkan, sedangkan slow path memanggil syscall untuk membentuk state pengurutan lintas thread yang diperlukan. Dokumentasi Linux menyebut library Read-Copy-Update dan garbage collector sebagai contoh sistem yang dapat memakai pola ini.
Pertukaran biaya tersebut tidak gratis. Expedited command memicu pekerjaan kernel dan overhead tambahan ketika dipanggil. Nilainya bergantung pada workload yang asimetris: sisi cepat perlu cukup sering dieksekusi dan sisi barrier cukup jarang agar pemindahan biaya memberi keuntungan.
Ini merupakan kondisi algoritmik, bukan klaim performa universal. Desain yang terlalu sering memanggil membarrier() dapat kehilangan keuntungan yang ingin dicapai.
Compiler barrier berbeda dari CPU memory barrier
Pola sinkronisasi ini bergantung pada perbedaan antara compiler ordering dan hardware memory ordering. Compiler barrier dapat mencegah compiler memindahkan operasi memori melintasi titik tertentu pada code hasil kompilasi, tetapi tidak sendirian memaksa core CPU lain mengamati akses memori dalam urutan yang diperlukan algoritma concurrent.
Full CPU memory barrier memberikan batas pengurutan pada hardware, tetapi menempatkannya pada setiap eksekusi fast path dapat mahal pada arsitektur atau workload tempat instruksi tersebut memiliki overhead yang berarti.
membarrier() menyediakan relasi pengurutan antara operasi barrier pemanggil dan akses memori oleh thread target. Mekanisme ini tidak menghapus kebutuhan untuk menalar compiler transformation, atomic operation, atau language memory model. Algoritma yang benar tetap memerlukan primitive pada level compiler dan bahasa yang sesuai di sekitar shared state.
Batas ini sangat penting pada C dan C++. Primitive ordering dari kernel tidak dapat mengubah program yang memiliki undefined behavior akibat data race menjadi valid menurut aturan bahasa.
Registrasi dan eksekusi adalah fase lifecycle terpisah
Bentuk dua command menciptakan batas lifecycle yang jelas. Registrasi merupakan operasi setup; eksekusi merupakan event sinkronisasi yang dapat terjadi berulang setelahnya.
Runtime dapat memeriksa dukungan, melakukan registrasi sekali, lalu mengaktifkan desain fast path yang mengandalkan private expedited barrier. Jika registrasi gagal, runtime dapat mempertahankan strategi sinkronisasi fallback daripada masuk ke mode yang kontrak ordering-nya tidak dapat dipenuhi.
Pemisahan ini juga mencegah EPERM saat eksekusi dianggap sebagai kegagalan scheduling sementara. Untuk private expedited, EPERM menandakan proses belum menyelesaikan registrasi yang diwajibkan.
Command set juga memiliki varian yang lebih kuat atau khusus. MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE menambahkan jaminan core serialization, sedangkan varian RSEQ dapat memulai ulang restartable-sequence critical section yang sedang berjalan. Command tersebut memiliki persyaratan registrasi dan dukungan tersendiri dan bukan alias untuk private expedited barrier dasar.
Barrier ini bukan primitive stop-the-world
Private expedited yang berhasil membentuk state ordering yang didokumentasikan, tetapi sibling thread tetap berjalan mengikuti scheduling normal. System call ini tidak menyediakan titik tempat aplikasi bebas membaca objek shared non-atomic tanpa sinkronisasi yang diwajibkan model concurrency program.
Operasi ini juga tidak menyediakan snapshot transaksional atas memori proses. Thread dapat terus mengubah shared state sebelum dan sesudah titik ordering. Algoritma yang memakai membarrier() tetap memerlukan protokol yang memberi arti pada event tersebut, misalnya mempublikasikan state sebelum pemanggilan dan menafsirkan observasi setelahnya sesuai aturan atomic serta compiler ordering milik algoritma.
Itulah batas utama interface ini: membarrier() dapat menyediakan event ordering berbantuan kernel secara efisien pada kumpulan thread yang terdefinisi, tetapi protokol concurrency di sekelilingnya tetap menentukan transisi state yang aman.