Saya pernah mendengar kata-kata ini yang berhubungan dengan pemrograman bersamaan, tetapi apa perbedaan di antara mereka?
Saya pernah mendengar kata-kata ini yang berhubungan dengan pemrograman bersamaan, tetapi apa perbedaan di antara mereka?
Jawaban:
Kunci hanya memungkinkan satu utas untuk memasuki bagian yang dikunci dan kunci tidak dibagi dengan proses lain.
Mutex sama dengan kunci tetapi bisa lebar sistem (dibagi oleh beberapa proses).
Sebuah semaphore melakukan hal yang sama seperti mutex tetapi memungkinkan x jumlah benang untuk masuk, ini dapat digunakan misalnya untuk membatasi jumlah cpu, io atau ram tugas-tugas intensif berjalan pada waktu yang sama.
Untuk posting yang lebih detail tentang perbedaan antara mutex dan semaphore baca di sini .
Anda juga memiliki kunci baca / tulis yang memungkinkan pembaca tanpa batas atau 1 penulis pada waktu tertentu.
Ada banyak kesalahpahaman tentang kata-kata ini.
Ini dari pos sebelumnya ( https://stackoverflow.com/a/24582076/3163691 ) yang sangat cocok di sini:
1) Bagian Kritis = Objek pengguna yang digunakan untuk memungkinkan pelaksanaan hanya satu utas aktif dari banyak lainnya dalam satu proses . Utas yang tidak dipilih lainnya (@ mendapatkan objek ini) dimatikan .
[Tidak ada kemampuan proses, objek yang sangat primitif].
2) Mutex Semaphore (alias Mutex) = Objek kernel yang digunakan untuk memungkinkan eksekusi hanya satu utas aktif dari banyak lainnya, di antara proses yang berbeda . Utas yang tidak dipilih lainnya (@ mendapatkan objek ini) dimatikan . Objek ini mendukung kepemilikan utas, pemberitahuan penghentian utas, rekursi (beberapa panggilan 'dapatkan' dari utas yang sama) dan 'penghindaran inversi prioritas'.
[Kemampuan interprocess, sangat aman digunakan, semacam objek sinkronisasi 'tingkat tinggi'].
3) Menghitung Semaphore (alias Semaphore) = Objek kernel yang digunakan untuk memungkinkan eksekusi sekelompok utas aktif dari banyak lainnya. Utas yang tidak dipilih lainnya (@ mendapatkan objek ini) dimatikan .
[Namun kemampuan interproses tidak terlalu aman untuk digunakan karena tidak memiliki atribut 'mutex' berikut: pemberitahuan penghentian utas, rekursi ?, 'penghindaran inversi prioritas'?, Dll].
4) Dan sekarang, berbicara tentang 'spinlocks', pertama beberapa definisi:
Wilayah Kritis = Wilayah memori yang digunakan bersama oleh 2 proses atau lebih.
Kunci = Variabel yang nilainya memungkinkan atau menolak pintu masuk ke 'wilayah kritis'. (Ini bisa diimplementasikan sebagai 'bendera boolean' yang sederhana).
Busy waiting = Pengujian variabel secara berkesinambungan hingga beberapa nilai muncul.
Akhirnya:
Spin-lock (alias Spinlock) = Kunci yang menggunakan menunggu sibuk . (Pengambilan kunci dilakukan oleh xchg atau operasi atom serupa ).
[Tanpa thread thread, kebanyakan digunakan hanya pada level kernel. Tidak efisien untuk kode level Pengguna].
Sebagai komentar terakhir, saya tidak yakin tetapi saya dapat bertaruh Anda banyak uang bahwa 3 objek sinkronisasi pertama di atas (# 1, # 2 dan # 3) menggunakan binatang sederhana ini (# 4) sebagai bagian dari implementasinya.
Semoga harimu menyenangkan!.
Referensi:
-Real-Time Konsep untuk Sistem Tertanam oleh Qing Li dengan Caroline Yao (CMP Books).
-Sistem Operasi Modern (3) oleh Andrew Tanenbaum (Pearson Education International).
-Pemrograman Aplikasi untuk Microsoft Windows (4) oleh Jeffrey Richter (Microsoft Programming Series).
Anda juga dapat melihat: https://stackoverflow.com/a/24586803/3163691
Sebagian besar masalah dapat diselesaikan dengan menggunakan (i) hanya mengunci, (ii) hanya semafor, ..., atau (iii) kombinasi keduanya! Seperti yang mungkin Anda temukan, keduanya sangat mirip: keduanya mencegah kondisi balapan , keduanya memiliki acquire()
/ release()
operasi, keduanya menyebabkan nol atau lebih utas menjadi tersumbat / dicurigai ... Sungguh, perbedaan yang krusial hanya terletak pada bagaimana mereka mengunci dan membuka kunci .
Untuk kedua kunci / semafor, mencoba menelepon acquire()
saat primitif dalam keadaan 0 menyebabkan utas penangguhan ditangguhkan. Untuk kunci - upaya untuk mendapatkan kunci dalam keadaan 1 berhasil. Untuk semafor - upaya untuk mendapatkan kunci di status {1, 2, 3, ...} berhasil.
Untuk kunci dalam keadaan 0, jika utas yang sama yang sebelumnya disebut acquire()
, sekarang panggilan rilis, maka rilis berhasil. Jika utas yang berbeda mencoba ini - ini tergantung pada implementasi / pustaka tentang apa yang terjadi (biasanya upaya diabaikan atau kesalahan dilemparkan). Untuk semafor dalam status 0, utas apa pun dapat memanggil rilis dan itu akan berhasil (terlepas dari utas mana yang sebelumnya digunakan untuk meletakkan semafor dalam status 0).
Dari diskusi sebelumnya, kita dapat melihat bahwa kunci memiliki gagasan tentang pemilik (utas satu-satunya yang dapat memanggil pelepasan adalah pemilik), sedangkan semafor tidak memiliki pemilik (utas apa pun dapat menyebut pelepasan pada semafor).
Apa yang menyebabkan banyak kebingungan adalah bahwa, dalam praktiknya ada banyak variasi definisi tingkat tinggi ini.
Variasi penting untuk dipertimbangkan :
acquire()
/ release()
disebut? - [Bervariasi secara masif ]Ini tergantung pada buku / dosen / bahasa / perpustakaan / lingkungan Anda.
Berikut ini adalah tur singkat yang mencatat bagaimana beberapa bahasa menjawab detail ini.
pthread_mutex_t
. Secara default, mereka tidak dapat dibagi dengan proses lain ( PTHREAD_PROCESS_PRIVATE
), namun mutex's memiliki atribut yang disebut berbagi . Saat disetel, maka mutex dibagi di antara proses ( PTHREAD_PROCESS_SHARED
).sem_t
. Mirip dengan mutex, semaphore dapat dibagi antara tiga proses banyak atau dirahasiakan dengan utas dari satu proses tunggal. Ini tergantung pada argumen berbagi yang disediakan untuk sem_init
.threading.RLock
) sebagian besar sama dengan C / C ++ pthread_mutex_t
s. Keduanya sama-sama reentrant . Ini berarti mereka hanya dapat dibuka oleh utas yang sama yang menguncinya. Ini adalah kasus bahwa sem_t
semaphore, threading.Semaphore
semaphores dan theading.Lock
kunci tidak reentrant - karena itu adalah setiap thread dapat melakukan membuka kunci kunci / turun semaphore.threading.Semaphore
) sebagian besar sama dengan sem_t
. Meskipun dengan sem_t
, antrian id benang digunakan untuk mengingat urutan di mana utas menjadi diblokir ketika mencoba untuk menguncinya saat dikunci. Ketika utas membuka semafor, utas pertama dalam antrian (jika ada) dipilih untuk menjadi pemilik baru. Pengenal utas dihapus dari antrian dan semafor menjadi terkunci lagi. Namun, dengan threading.Semaphore
, set digunakan sebagai ganti antrian, sehingga urutan di mana utas menjadi diblokir tidak disimpan - utas apa pun dalam set dapat dipilih untuk menjadi pemilik berikutnya.java.util.concurrent.ReentrantLock
) sebagian besar sama dengan C / C ++ pthread_mutex_t
's, dan Python threading.RLock
dalam hal itu juga menerapkan kunci reentrant. Berbagi kunci antar proses lebih sulit di Jawa karena JVM bertindak sebagai perantara. Jika utas mencoba membuka kunci kunci yang bukan miliknya, sebuahIllegalMonitorStateException
dilemparkan.java.util.concurrent.Semaphore
) sebagian besar sama dengan sem_t
dan threading.Semaphore
. Konstruktor untuk Java semaphores menerima parameter fairness boolean yang mengontrol apakah akan menggunakan set (false) atau antrian (true) untuk menyimpan utas menunggu. Secara teori, semaphore sering dibahas, tetapi dalam praktiknya, semaphores tidak banyak digunakan. Semafor hanya menyimpan status satu bilangan bulat, sehingga seringkali agak tidak fleksibel dan banyak yang diperlukan sekaligus - menyebabkan kesulitan dalam memahami kode. Juga, fakta bahwa utas apa pun dapat melepaskan semaphore terkadang tidak diinginkan. Lebih banyak primitif / abstraksi sinkronisasi berorientasi objek / tingkat tinggi seperti "variabel kondisi" dan "monitor" yang digunakan.
Lihatlah Tutorial Multithreading oleh John Kopplin.
Di bagian Sinkronisasi Antar Utas , ia menjelaskan perbedaan antara acara, kunci, mutex, semaphore, penghitung waktu tunggu
Sebuah mutex dapat dimiliki oleh hanya satu thread pada satu waktu, yang memungkinkan benang untuk mengkoordinasikan akses eksklusif ke sumber daya bersama
Objek bagian kritis menyediakan sinkronisasi yang sama dengan yang disediakan oleh objek mutex, kecuali bahwa objek bagian kritis hanya dapat digunakan oleh utas proses tunggal
Perbedaan lain antara mutex dan bagian kritis adalah bahwa jika objek bagian kritis saat ini dimiliki oleh utas lain,
EnterCriticalSection()
menunggu tanpa batas waktu kepemilikan sedangkanWaitForSingleObject()
, yang digunakan dengan mutex, memungkinkan Anda untuk menentukan batas waktuSebuah semaphore mempertahankan hitungan antara nol dan beberapa nilai maksimum, membatasi jumlah thread yang bersamaan mengakses sumber daya bersama.
Saya akan mencoba menutupinya dengan contoh:
Kunci: Salah satu contoh di mana Anda akan menggunakan lock
kamus yang dibagikan di mana item (yang harus memiliki kunci unik) ditambahkan.
Kunci akan memastikan bahwa satu utas tidak memasukkan mekanisme kode yang memeriksa item dalam kamus, sedangkan utas lainnya (yang ada di bagian kritis) telah melewati pemeriksaan ini dan menambahkan item. Jika utas lain mencoba memasukkan kode yang dikunci, ia akan menunggu (diblokir) hingga objek dilepaskan.
private static readonly Object obj = new Object();
lock (obj) //after object is locked no thread can come in and insert item into dictionary on a different thread right before other thread passed the check...
{
if (!sharedDict.ContainsKey(key))
{
sharedDict.Add(item);
}
}
Semaphore: Katakanlah Anda memiliki kumpulan koneksi, maka utas tunggal mungkin mencadangkan satu elemen di kumpulan dengan menunggu semaphore untuk mendapatkan koneksi. Kemudian menggunakan koneksi dan ketika pekerjaan selesai melepaskan koneksi dengan merilis semaphore.
Contoh kode yang saya sukai adalah salah satu bouncer yang diberikan oleh @Patric - begini:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace TheNightclub
{
public class Program
{
public static Semaphore Bouncer { get; set; }
public static void Main(string[] args)
{
// Create the semaphore with 3 slots, where 3 are available.
Bouncer = new Semaphore(3, 3);
// Open the nightclub.
OpenNightclub();
}
public static void OpenNightclub()
{
for (int i = 1; i <= 50; i++)
{
// Let each guest enter on an own thread.
Thread thread = new Thread(new ParameterizedThreadStart(Guest));
thread.Start(i);
}
}
public static void Guest(object args)
{
// Wait to enter the nightclub (a semaphore to be released).
Console.WriteLine("Guest {0} is waiting to entering nightclub.", args);
Bouncer.WaitOne();
// Do some dancing.
Console.WriteLine("Guest {0} is doing some dancing.", args);
Thread.Sleep(500);
// Let one guest out (release one semaphore).
Console.WriteLine("Guest {0} is leaving the nightclub.", args);
Bouncer.Release(1);
}
}
}
Mutex Ini cukup banyak Semaphore(1,1)
dan sering digunakan secara global (lebar aplikasi kalau tidak bisa dibilang lock
lebih tepat). Seseorang akan menggunakan global Mutex
ketika menghapus node dari daftar yang dapat diakses secara global (hal terakhir yang Anda ingin utas lainnya melakukan sesuatu saat Anda menghapus node). Ketika Anda memperoleh Mutex
jika utas yang berbeda mencoba mengakuisisi yang sama, Mutex
ia akan ditidurkan hingga utas SAMA yang memperoleh Mutex
pelepasannya.
Contoh yang bagus untuk membuat mutex global adalah oleh @deepee
class SingleGlobalInstance : IDisposable
{
public bool hasHandle = false;
Mutex mutex;
private void InitMutex()
{
string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value.ToString();
string mutexId = string.Format("Global\\{{{0}}}", appGuid);
mutex = new Mutex(false, mutexId);
var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);
var securitySettings = new MutexSecurity();
securitySettings.AddAccessRule(allowEveryoneRule);
mutex.SetAccessControl(securitySettings);
}
public SingleGlobalInstance(int timeOut)
{
InitMutex();
try
{
if(timeOut < 0)
hasHandle = mutex.WaitOne(Timeout.Infinite, false);
else
hasHandle = mutex.WaitOne(timeOut, false);
if (hasHandle == false)
throw new TimeoutException("Timeout waiting for exclusive access on SingleInstance");
}
catch (AbandonedMutexException)
{
hasHandle = true;
}
}
public void Dispose()
{
if (mutex != null)
{
if (hasHandle)
mutex.ReleaseMutex();
mutex.Dispose();
}
}
}
kemudian gunakan seperti:
using (new SingleGlobalInstance(1000)) //1000ms timeout on global lock
{
//Only 1 of these runs at a time
GlobalNodeList.Remove(node)
}
Semoga ini menghemat waktu Anda.
Wikipedia memiliki bagian yang bagus tentang perbedaan antara Semaphores dan Mutex :
Mutex pada dasarnya adalah hal yang sama dengan semaphore biner dan kadang-kadang menggunakan implementasi dasar yang sama. Perbedaan di antara mereka adalah:
Mutex memiliki konsep pemilik, yaitu proses yang mengunci mutex. Hanya proses yang mengunci mutex yang dapat membukanya. Sebaliknya, semafor tidak memiliki konsep pemilik. Setiap proses dapat membuka kunci semaphore.
Tidak seperti semaphore, mutex memberikan keamanan inversi prioritas. Karena mutex mengetahui pemiliknya saat ini, dimungkinkan untuk mempromosikan prioritas pemiliknya setiap kali tugas dengan prioritas lebih tinggi mulai menunggu di mutex.
Mutex juga memberikan keamanan penghapusan, di mana proses memegang mutex tidak dapat dihapus secara tidak sengaja. Semafor tidak menyediakan ini.
Pemahaman saya adalah bahwa mutex hanya untuk digunakan dalam satu proses tunggal, tetapi di banyak utasnya, sedangkan semafor dapat digunakan di berbagai proses, dan di seluruh rangkaian utasnya.
Juga, mutex adalah biner (baik terkunci atau tidak terkunci), sedangkan semaphore memiliki gagasan tentang penghitungan, atau antrian lebih dari satu permintaan kunci dan membuka kunci.
Bisakah seseorang memverifikasi penjelasan saya? Saya berbicara dalam konteks Linux, khususnya Red Hat Enterprise Linux (RHEL) versi 6, yang menggunakan kernel 2.6.32.
Menggunakan pemrograman C pada varian Linux sebagai contoh dasar untuk contoh.
Mengunci:
• Biasanya biner konstruksi yang sangat sederhana dalam operasi terkunci atau tidak terkunci
• Tidak ada konsep kepemilikan utas, prioritas, pengurutan dll.
• Biasanya kunci putaran di mana utas terus-menerus memeriksa ketersediaan kunci.
• Biasanya bergantung pada operasi atom misalnya Uji-dan-set, bandingkan-dan-tukar, ambil-dan-tambah dll.
• Biasanya memerlukan dukungan perangkat keras untuk operasi atom.
File Locks:
• Biasanya digunakan untuk mengoordinasikan akses ke file melalui berbagai proses.
• Beberapa proses dapat menahan kunci baca namun ketika proses tunggal menahan kunci tulis tidak ada proses lain yang diizinkan untuk mendapatkan kunci baca atau tulis.
• Contoh: kawanan, fcntl dll.
Mutex:
• Panggilan fungsi mutex biasanya bekerja di ruang kernel dan menghasilkan panggilan sistem.
• Menggunakan konsep kepemilikan. Hanya utas yang saat ini memegang mutex yang dapat membukanya.
• Mutex tidak bersifat rekursif (Pengecualian: PTHREAD_MUTEX_RECURSIVE).
• Biasanya digunakan dalam Asosiasi dengan Variabel Kondisi dan diteruskan sebagai argumen untuk misalnya pthread_cond_signal, pthread_cond_wait dll.
• Beberapa sistem UNIX memungkinkan mutex untuk digunakan oleh beberapa proses meskipun ini mungkin tidak diberlakukan pada semua sistem.
Tiang sinyal:
• Ini adalah integer yang dikelola kernel yang nilainya tidak diperbolehkan turun di bawah nol.
• Dapat digunakan untuk menyinkronkan proses.
• Nilai semaphore dapat diatur ke nilai yang lebih besar dari 1 dalam hal nilai biasanya menunjukkan jumlah sumber daya yang tersedia.
• Semafor yang nilainya terbatas pada 1 dan 0 disebut sebagai semaphore biner.
Supporting ownership
, maximum number of processes share lock
dan maximum number of allowed processes/threads in critical section
tiga faktor utama yang menentukan nama / jenis objek bersamaan dengan nama umum lock
. Karena nilai dari faktor-faktor ini adalah biner (memiliki dua status), kita dapat meringkasnya dalam tabel 3 * 8 seperti kebenaran.
X Y Z Name
--- --- --- ------------------------
0 ∞ ∞ Semaphore
0 ∞ 1 Binary Semaphore
0 1 ∞ SemaphoreSlim
0 1 1 Binary SemaphoreSlim(?)
1 ∞ ∞ Recursive-Mutex(?)
1 ∞ 1 Mutex
1 1 ∞ N/A(?)
1 1 1 Lock/Monitor
Merasa bebas untuk mengedit atau memperluas tabel ini, saya telah mempostingnya sebagai tabel ascii untuk dapat diedit :)