Jawaban:
Spinlock dan semaphore berbeda terutama dalam empat hal:
1. Apa mereka
A spinlock adalah salah satu kemungkinan implementasi dari kunci, yaitu salah satu yang dilaksanakan oleh tunggu sibuk ( "berputar"). Semaphore adalah generalisasi kunci (atau, sebaliknya, kunci adalah kasus khusus dari semaphore). Biasanya, tetapi tidak harus , spinlock hanya valid dalam satu proses sedangkan semaphore dapat digunakan untuk menyinkronkan antara proses yang berbeda juga.
Kunci berfungsi untuk saling pengecualian, yaitu satu utas pada satu waktu dapat memperoleh kunci dan melanjutkan dengan "bagian kritis" kode. Biasanya, ini berarti kode yang mengubah beberapa data yang dibagikan oleh beberapa utas.
Sebuah semaphore memiliki counter dan akan membiarkan dirinya diakuisisi oleh satu atau beberapa thread, tergantung pada nilai apa yang Anda posting untuk itu, dan (dalam beberapa implementasi) tergantung pada nilai apa yang diijinkan maksimum adalah.
Sejauh ini, seseorang dapat menganggap kunci sebagai kasus khusus dari semaphore dengan nilai maksimum 1.
2. Apa yang mereka lakukan
Seperti yang dinyatakan di atas, spinlock adalah kunci, dan oleh karena itu merupakan mekanisme pengecualian timbal balik (ketat 1 ke 1). Ia bekerja dengan berulang kali menanyakan dan / atau memodifikasi lokasi memori, biasanya dengan cara yang sama. Ini berarti bahwa memperoleh spinlock adalah operasi "sibuk" yang mungkin membakar siklus CPU untuk waktu yang lama (mungkin selamanya!) Sementara secara efektif menghasilkan "tidak ada".
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 efisien. Selain itu, untuk aplikasi waktu nyata, mungkin tidak dapat diterima untuk memblokir dan menunggu penjadwal kembali lagi di waktu yang jauh di masa mendatang.
Semaphore, sebaliknya, tidak berputar sama sekali, atau hanya berputar untuk waktu yang sangat singkat (sebagai pengoptimalan untuk menghindari overhead syscall). Jika semaphore tidak dapat diperoleh, itu memblokir, memberikan waktu CPU ke utas berbeda yang siap dijalankan. Ini tentu saja mungkin berarti bahwa beberapa milidetik berlalu sebelum utas Anda dijadwalkan lagi, tetapi jika ini tidak ada masalah (biasanya tidak) maka ini bisa menjadi pendekatan yang sangat efisien dan konservatif CPU.
3. Bagaimana mereka berperilaku di hadapan kemacetan
Ini adalah kesalahpahaman umum bahwa spinlock atau algoritma bebas kunci "umumnya lebih cepat", atau bahwa mereka hanya berguna untuk "tugas yang sangat singkat" (idealnya, tidak ada objek sinkronisasi yang harus ditahan lebih lama dari yang benar-benar diperlukan).
Satu perbedaan penting adalah bagaimana pendekatan yang berbeda berperilaku saat terjadi kemacetan .
Sistem yang dirancang dengan baik biasanya memiliki sedikit atau tidak ada kemacetan (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 mengurai data, dan akhirnya memodifikasi referensi bersama (menambahkan data ke wadah, dll.) sebelum membuka 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, tentu saja kemungkinan utas berada di dalam bagian kritis relatif rendah, dan dengan demikian beberapa utas bersaing untuk mendapatkan kunci pada saat yang bersamaan. Tentu saja sesekali dua utas akan mencoba mendapatkan kunci pada saat yang sama (jika ini tidak bisa terjadi, Anda tidak akan 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, overhead memperoleh spinlock hanyalah selusin siklus dibandingkan dengan ratusan / ribuan siklus untuk sakelar konteks atau 10-20 juta siklus untuk kehilangan sisa potongan waktu.
Di sisi lain, karena 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.
Semaphore (atau mutex) adalah pilihan yang jauh lebih baik dalam hal ini, karena memungkinkan utas yang berbeda untuk menjalankan tugas yang berguna selama waktu itu. Atau, jika tidak ada thread lain yang berguna untuk dilakukan, hal ini memungkinkan sistem operasi untuk memperlambat CPU dan mengurangi panas / menghemat energi.
Selain itu, pada sistem inti tunggal, spinlock akan menjadi sangat tidak efisien dengan adanya kemacetan kunci, karena utas pemintalan akan membuang-buang waktunya menunggu perubahan status yang tidak mungkin terjadi (tidak sampai utas pelepasan dijadwalkan, yang tidak tidak terjadi saat thread menunggu berjalan!). Oleh karena itu, mengingat setiap jumlah pertentangan, memperoleh kunci membutuhkan waktu sekitar 1 1/2 irisan waktu dalam kasus terbaik (dengan asumsi benang melepaskan adalah yang berikutnya yang dijadwalkan), yang tidak perilaku yang sangat baik.
4. Bagaimana mereka diimplementasikan
Semaphore saat ini biasanya akan membungkus sys_futex
di Linux (opsional dengan spinlock yang keluar setelah beberapa kali mencoba).
Spinlock biasanya diimplementasikan menggunakan operasi atom, dan tanpa menggunakan apa pun yang disediakan oleh sistem operasi. Di masa lalu, ini berarti menggunakan instruksi compiler intrinsics atau non-portable assembler. Sementara itu C ++ 11 dan C11 memiliki operasi atomik 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 tanpa rasa sakit.
sederhananya, semaphore adalah objek sinkronisasi yang "menghasilkan", spinlock adalah objek 'busywait'. (ada sedikit lebih banyak pada semaphore karena mereka menyinkronkan beberapa utas, tidak seperti mutex atau penjaga atau monitor atau bagian penting yang melindungi wilayah kode dari satu utas)
Anda akan menggunakan semaphore dalam lebih banyak keadaan, tetapi gunakan spinlock di mana Anda akan mengunci untuk waktu yang sangat singkat - ada biaya untuk mengunci terutama jika Anda banyak mengunci. Dalam kasus seperti itu, akan lebih efisien untuk memutar kunci sebentar sambil menunggu sumber daya yang dilindungi dibuka kuncinya. Jelas ada kinerja yang memukul jika Anda berputar terlalu lama.
biasanya jika Anda berputar lebih lama dari kuantum utas, maka Anda harus menggunakan semafor.
Di atas dan di atas apa yang dikatakan Yoav Aviram dan gbjbaanb, poin penting lainnya dulu 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 dalam keadaan di mana Anda hanya memiliki satu CPU, Anda harus menggunakan semaphores. (Saya percaya alasannya jelas. Jika CPU tunggal sibuk menunggu sesuatu yang lain untuk melepaskan spin-lock, tetapi berjalan pada satu-satunya CPU, kunci tersebut tidak mungkin dilepaskan sampai proses atau utas saat ini didahului oleh O / S, yang mungkin membutuhkan waktu beberapa saat dan tidak ada hal berguna yang terjadi sampai preemption terjadi.)
Saya bukan ahli kernel tetapi berikut beberapa poinnya:
Bahkan mesin uniprocessor dapat menggunakan spin-locks jika kernel preemption diaktifkan saat mengkompilasi kernel. Jika preemption kernel dinonaktifkan maka spin-lock (mungkin) meluas ke pernyataan void .
Juga, ketika kami mencoba membandingkan Semaphore vs Spin-lock, saya percaya semaphore mengacu pada yang digunakan di kernel - BUKAN yang digunakan untuk IPC (userland).
Pada dasarnya, spin-lock harus digunakan jika bagian kritis kecil (lebih kecil dari overhead tidur / bangun) dan bagian kritis tidak memanggil apapun yang dapat tidur! Semaphore harus digunakan jika bagian kritis lebih besar dan bisa tidur.
Raman Chalotra.
Spinlock mengacu pada implementasi penguncian antar-utas menggunakan instruksi perakitan yang bergantung pada mesin (seperti test-and-set). Ini disebut spinlock karena utas hanya menunggu dalam satu putaran ("berputar") berulang kali memeriksa hingga kunci tersedia (menunggu sibuk). Spinlock digunakan sebagai pengganti mutex, yang merupakan fasilitas yang disediakan oleh sistem operasi (bukan CPU), karena spinlock bekerja lebih baik, jika dikunci dalam waktu singkat.
Semaphor adalah fasilitas yang disediakan oleh sistem operasi untuk IPC, oleh karena itu tujuan utamanya adalah komunikasi antar proses. Menjadi fasilitas yang disediakan oleh sistem operasi, kinerjanya tidak akan sebaik spinlock untuk penguncian antar-thead (meskipun mungkin). Semaphore lebih baik untuk mengunci untuk jangka waktu yang lebih lama.
Yang mengatakan - menerapkan splinlock dalam perakitan itu rumit, dan tidak portabel.
Saya ingin menambahkan pengamatan saya, yang lebih umum dan tidak terlalu spesifik untuk Linux.
Bergantung pada arsitektur memori dan kemampuan prosesor, Anda mungkin memerlukan spin-lock untuk mengimplementasikan semaphore pada sistem multi-core atau multiprosesor, karena dalam sistem seperti itu kondisi balapan dapat terjadi ketika dua atau lebih thread / proses menginginkan untuk mendapatkan semaphore.
Ya, jika arsitektur memori Anda menawarkan penguncian bagian memori oleh satu inti / prosesor yang menunda semua akses lainnya, dan jika prosesor Anda menawarkan uji-dan-set, Anda dapat mengimplementasikan semaphore tanpa spin-lock (tetapi dengan sangat hati-hati! ).
Namun, karena sistem multi-core yang sederhana / murah dirancang (saya bekerja di sistem tertanam), tidak semua arsitektur memori mendukung fitur multi-core / multiprosesor, hanya test-and-set atau yang setara. Maka implementasinya bisa jadi sebagai berikut:
Merilis semaphore perlu diimplementasikan sebagai berikut:
Ya, dan untuk semaphore biner sederhana pada level OS, hanya mungkin menggunakan spin-lock sebagai penggantinya. Tetapi hanya jika bagian kode yang akan dilindungi benar-benar sangat kecil.
Seperti yang dikatakan sebelumnya, jika dan saat Anda menerapkan OS Anda sendiri, pastikan untuk berhati-hati. Debugging kesalahan seperti itu menyenangkan (pendapat saya, tidak dibagikan oleh banyak orang), tetapi kebanyakan sangat membosankan dan sulit.
"Mutex" (atau "mutual exclusion lock") adalah sinyal yang dapat digunakan oleh dua atau lebih proses asinkron untuk mencadangkan sumber daya bersama untuk penggunaan eksklusif. Proses pertama yang memperoleh kepemilikan "mutex" juga memperoleh kepemilikan sumber daya bersama. Proses lain harus menunggu proses pertama untuk melepaskan kepemilikan "mutex" itu sebelum mereka mencoba untuk mendapatkannya.
Primitif penguncian yang paling umum di kernel adalah spinlock. Spinlock adalah kunci dudukan tunggal yang sangat sederhana. Jika suatu proses mencoba memperoleh spinlock dan tidak tersedia, proses tersebut akan terus mencoba (berputar) sampai dapat memperoleh kunci. Kesederhanaan ini menciptakan kunci kecil dan cepat.
Spinlock digunakan jika dan hanya jika Anda cukup yakin bahwa hasil yang Anda harapkan akan terjadi segera, sebelum waktu pemotongan eksekusi thread Anda berakhir.
Contoh: Dalam modul device driver, Driver menulis "0" di hardware Register R0 dan sekarang harus menunggu register R0 menjadi 1. H / W membaca R0 dan melakukan beberapa pekerjaan dan menulis "1" di R0. Ini biasanya cepat (dalam mikro detik). Sekarang berputar jauh lebih baik daripada tidur dan diinterupsi oleh H / W. Tentu saja, saat berputar, kondisi kegagalan H / W perlu diperhatikan!
Sama sekali tidak ada alasan bagi aplikasi pengguna untuk berputar. Ini tidak masuk akal. Anda akan berputar agar suatu peristiwa terjadi dan peristiwa itu perlu diselesaikan oleh aplikasi tingkat pengguna lain yang tidak pernah dijamin akan terjadi dalam kerangka waktu yang cepat. Jadi, saya tidak akan berputar sama sekali dalam mode pengguna. Saya lebih baik tidur () atau mutexlock () atau kunci semaphore () dalam mode pengguna.
Dari apa perbedaan antara kunci putar dan semaphore? oleh Maciej Piechotka :
Keduanya mengelola sumber daya yang terbatas. Saya pertama-tama akan menjelaskan perbedaan antara binary semaphore (mutex) dan spin lock.
Kunci putar melakukan menunggu sibuk - yaitu terus menjalankan loop:
while (try_acquire_resource ()); ... melepaskan();Ini melakukan penguncian / pembukaan kunci yang sangat ringan tetapi jika utas penguncian akan didahului oleh yang lain yang akan mencoba mengakses sumber daya yang sama, yang kedua hanya akan mencoba untuk membebaskan sumber daya sampai kehabisan kuanta CPU.
Di sisi lain mutex berperilaku lebih seperti:if (! try_lock ()) { add_to_waiting_queue (); Tunggu(); } ... proses * p = get_next_process_from_waiting_queue (); p-> bangun ();Oleh karena itu, jika utas akan mencoba memperoleh sumber daya yang diblokir, utas akan ditangguhkan sampai tersedia untuk itu. Mengunci / membuka kunci jauh lebih berat tetapi penantiannya 'gratis' dan 'adil'.
Semaphore adalah kunci yang diizinkan untuk digunakan beberapa kali (diketahui dari inisialisasi) beberapa kali - misalnya 3 utas diizinkan untuk memegang sumber daya secara bersamaan tetapi tidak lebih. Ini digunakan misalnya dalam masalah produsen / konsumen atau secara umum dalam antrian:
P (resource_sem) resource = resources.pop () ... resources.push (resource) V (resource_sem)
spin_trylock
, yang segera kembali dengan kode kesalahan, jika kunci tidak dapat diperoleh. Spin-lock tidak selalu sekeras itu. Tetapi menggunakanspin_trylock
membutuhkan, untuk aplikasi, untuk dirancang dengan benar seperti itu (mungkin antrian operasi yang tertunda, dan di sini, memilih yang berikutnya, meninggalkan yang sebenarnya di antrian).