Spinlock dan semafor berbeda terutama dalam empat hal:
Sebuah spinlock adalah salah satu implementasi yang mungkin dari sebuah kunci, yaitu yang diimplementasikan dengan menunggu sibuk ("berputar"). Sebuah semafor adalah generalisasi dari kunci (atau, sebaliknya, kunci adalah kasus khusus dari sebuah semafor). Biasanya, tetapi tidak harus , spinlock hanya valid dalam satu proses sedangkan semafor juga dapat digunakan untuk menyinkronkan antara proses yang berbeda.
Kunci berfungsi untuk pengecualian timbal balik, yaitu satu utas sekaligus dapat memperoleh kunci dan melanjutkan dengan "bagian kritis" kode. Biasanya, ini berarti kode yang memodifikasi beberapa data yang dibagikan oleh beberapa utas.
Sebuah semafor memiliki penghitung dan akan membiarkan dirinya diakuisisi oleh satu atau beberapa utas, bergantung pada nilai yang Anda poskan padanya, dan (dalam beberapa implementasi) bergantung pada nilai maksimum yang diizinkan.
Sejauh ini, seseorang dapat menganggap kunci sebagai kasus khusus semafor dengan nilai maksimum 1.
Seperti yang dinyatakan di atas, spinlock adalah kunci, dan oleh karena itu merupakan mekanisme pengecualian timbal balik (ketatnya 1 banding 1). Ini bekerja dengan berulang kali menanyakan dan/atau memodifikasi lokasi memori, biasanya dengan cara atomik. Ini berarti bahwa memperoleh spinlock adalah operasi "sibuk" yang mungkin membakar siklus CPU untuk waktu yang lama (mungkin selamanya!) sementara secara efektif tidak mencapai "apa-apa".
Insentif utama untuk pendekatan semacam itu adalah kenyataan bahwa sakelar konteks memiliki overhead yang setara dengan pemintalan beberapa ratus (atau mungkin ribuan) kali, jadi jika kunci dapat diperoleh dengan membakar beberapa siklus pemintalan, ini mungkin secara keseluruhan sangat baik. lebih hemat. Selain itu, untuk aplikasi waktu nyata, mungkin tidak dapat diterima untuk memblokir dan menunggu penjadwal kembali ke aplikasi tersebut di waktu yang jauh di masa mendatang.
Semafor, sebaliknya, tidak berputar sama sekali, atau hanya berputar untuk waktu yang sangat singkat (sebagai pengoptimalan untuk menghindari overhead syscall). Jika semaphore tidak dapat diperoleh, semaphore akan diblokir, memberikan waktu CPU ke thread lain yang siap dijalankan. Ini tentu saja dapat berarti bahwa beberapa milidetik berlalu sebelum utas Anda dijadwalkan lagi, tetapi jika ini bukan masalah (biasanya tidak) maka ini bisa menjadi pendekatan hemat CPU yang sangat efisien.
Ini adalah kesalahpahaman umum bahwa algoritme spinlock atau bebas kunci "umumnya lebih cepat", atau bahwa algoritme tersebut hanya berguna untuk "tugas yang sangat singkat" (idealnya, tidak ada objek sinkronisasi yang boleh disimpan lebih lama dari yang benar-benar diperlukan).
Satu perbedaan penting adalah bagaimana pendekatan yang berbeda berperilaku di hadapan kemacetan .
Sistem yang dirancang dengan baik biasanya memiliki kemacetan rendah atau tidak ada (ini berarti tidak semua utas mencoba mendapatkan kunci pada waktu yang sama). Misalnya, seseorang biasanya tidak menulis kode yang memperoleh kunci, lalu memuat setengah megabyte data terkompresi zip dari jaringan, mendekode dan mem-parsing data, dan terakhir memodifikasi referensi bersama (menambahkan data ke wadah, dll.) sebelum melepaskan kunci. Sebaliknya, seseorang akan memperoleh kunci hanya untuk tujuan mengakses sumber daya bersama .
Karena ini berarti ada lebih banyak pekerjaan di luar bagian kritis daripada di dalamnya, secara alami kemungkinan utas berada di dalam bagian kritis relatif rendah, dan dengan demikian hanya sedikit utas yang bersaing untuk mengunci pada saat yang sama. Tentu saja sesekali dua utas akan mencoba mendapatkan kunci pada saat yang sama (jika ini tidak bisa kebetulan Anda tidak memerlukan kunci!), tetapi ini lebih merupakan pengecualian daripada aturan dalam sistem "sehat".
Dalam kasus seperti itu, spinlock sangat mengungguli semaphore karena jika tidak ada kemacetan kunci, biaya tambahan untuk memperoleh spinlock hanya selusin siklus dibandingkan dengan ratusan/ribuan siklus untuk sakelar konteks atau 10-20 juta siklus untuk kehilangan sisa irisan waktu.
Di sisi lain, mengingat kemacetan tinggi, atau jika kunci ditahan untuk waktu yang lama (terkadang Anda tidak bisa menahannya!), Spinlock akan membakar siklus CPU dalam jumlah yang tidak masuk akal karena tidak mencapai apa-apa.
Sebuah semaphore (atau mutex) adalah pilihan yang jauh lebih baik dalam kasus ini, karena memungkinkan thread yang berbeda untuk berjalan berguna tugas selama itu. Atau, jika tidak ada utas lain yang berguna untuk dilakukan, ini memungkinkan sistem operasi untuk memperlambat CPU dan mengurangi panas/menghemat energi.
Selain itu, pada sistem inti tunggal, spinlock akan sangat tidak efisien dengan adanya kemacetan kunci, karena utas pemintalan akan menghabiskan waktu sepenuhnya untuk menunggu perubahan keadaan yang tidak mungkin terjadi (tidak sampai utas pelepasan dijadwalkan, yang tidak terjadi saat utas menunggu sedang berjalan!). Oleh karena itu, berikan apa saja jumlah perselisihan, memperoleh kunci membutuhkan sekitar 1 1/2 irisan waktu dalam kasus terbaik (dengan asumsi utas pelepasan adalah utas berikutnya yang dijadwalkan), yang merupakan perilaku yang tidak terlalu baik.
Sebuah semafor saat ini biasanya membungkus sys_futex
di Linux (opsional dengan spinlock yang keluar setelah beberapa upaya).
Spinlock biasanya diimplementasikan menggunakan operasi atom, dan tanpa menggunakan apa pun yang disediakan oleh sistem operasi. Di masa lalu, ini berarti menggunakan intrinsik compiler atau instruksi assembler non-portabel. Sementara itu baik C++ 11 dan C11 memiliki operasi atom sebagai bagian dari bahasa, jadi terlepas dari kesulitan umum dalam menulis kode bebas kunci yang terbukti benar, sekarang dimungkinkan untuk mengimplementasikan kode bebas kunci dalam perangkat yang sepenuhnya portabel dan (hampir) cara yang tidak menyakitkan.
Di atas apa yang dikatakan Yoav Aviram dan gbjbaanb, poin kunci lainnya adalah bahwa Anda tidak akan pernah menggunakan spin-lock pada mesin CPU tunggal, sedangkan semaphore akan masuk akal pada mesin seperti itu. Saat ini, Anda sering kesulitan menemukan mesin tanpa banyak inti, atau hyperthreading, atau yang setara, tetapi jika Anda hanya memiliki satu CPU, Anda harus menggunakan semafor. (Saya yakin alasannya jelas. Jika satu CPU sibuk menunggu sesuatu yang lain untuk melepaskan spin-lock, tetapi itu berjalan pada satu-satunya CPU, kunci tidak mungkin dilepaskan sampai proses atau utas saat ini didahului oleh O/S, yang mungkin memakan waktu cukup lama dan tidak ada hal berguna yang terjadi hingga preemption terjadi.)
sangat sederhana, semafor adalah objek sinkronisasi "menghasilkan", spinlock adalah objek 'sibuk menunggu'. (ada sedikit lebih ke semafor karena menyinkronkan beberapa utas, tidak seperti mutex atau penjaga atau monitor atau bagian penting yang melindungi wilayah kode dari satu utas)
Anda akan menggunakan semafor dalam lebih banyak keadaan, tetapi gunakan spinlock di mana Anda akan mengunci untuk waktu yang sangat singkat - ada biaya untuk mengunci terutama jika Anda mengunci banyak. Dalam kasus seperti itu, akan lebih efisien untuk melakukan spinlock sebentar sambil menunggu sumber daya yang dilindungi dibuka kuncinya. Jelas ada penurunan performa jika Anda berputar terlalu lama.
biasanya jika Anda memutar lebih dari satu kuantum utas, maka Anda harus menggunakan semafor.