Yanıtlar:
Kilitler karşılıklı dışlama için kullanılır. Bir kod parçasının atomik olduğundan emin olmak istediğinizde, etrafına bir kilit koyun. Bunu yapmak için teorik olarak bir ikili semafor kullanabilirsiniz, ancak bu özel bir durumdur.
Semaforlar ve koşul değişkenleri, kilitler tarafından sağlanan karşılıklı dışlamanın üzerine inşa edilir ve paylaşılan kaynaklara senkronize erişim sağlamak için kullanılır. Benzer amaçlar için kullanılabilirler.
Bir koşul değişkeni, genellikle bir kaynağın kullanılabilir olmasını beklerken meşgul beklemeden (bir koşulu kontrol ederken tekrar tekrar döngü) kaçınmak için kullanılır. Örneğin, bir kuyruk boşalana kadar devam edemeyen bir iş parçacığına (veya birden çok iş parçacığına) sahipseniz, meşgul bekleme yaklaşımı aşağıdaki gibi bir şey yapmak olacaktır:
//pseudocode
while(!queue.empty())
{
sleep(1);
}
Bununla ilgili sorun, bu iş parçacığının durumu tekrar tekrar kontrol etmesini sağlayarak işlemci zamanını boşa harcıyor olmanızdır. Neden bunun yerine iş parçacığına kaynağın mevcut olduğunu bildirmek için sinyal verilebilecek bir senkronizasyon değişkenine sahip değilsiniz?
//pseudocode
syncVar.lock.acquire();
while(!queue.empty())
{
syncVar.wait();
}
//do stuff with queue
syncVar.lock.release();
Muhtemelen, başka bir yerde işleri sıranın dışına çeken bir iş parçacığına sahip olacaksınız. Sıra boş olduğunda, syncVar.signal()
uykuda duran rastgele bir iş parçacığını uyandırmak için çağrı yapabilir syncVar.wait()
(veya genellikle bekleyen tüm iş parçacıklarını uyandırmak için bir signalAll()
veya broadcast()
yöntem de vardır).
Tek bir koşulda bekleyen bir veya daha fazla iş parçacığım olduğunda (örneğin kuyruğun boş olması için) genellikle bunun gibi senkronizasyon değişkenlerini kullanırım.
Semaforlar benzer şekilde kullanılabilir, ancak bazı tam sayıdaki mevcut şeylere bağlı olarak mevcut ve kullanılamayan paylaşılan bir kaynağınız olduğunda daha iyi kullanıldığını düşünüyorum. Semaforlar, üreticilerin kaynakları tahsis ettiği ve tüketicilerin bunları tükettiği üretici / tüketici durumları için iyidir.
Bir gazoz otomatınız olup olmadığını düşünün. Yalnızca bir soda makinesi var ve bu paylaşılan bir kaynak. Makineyi stokta tutmaktan sorumlu satıcı (üretici) olan bir iş parçacığına ve makineden gazlı içecekler almak isteyen alıcılar (tüketiciler) olan N iş parçacığına sahipsiniz. Makinedeki gazlı içecek sayısı semaforumuzu çalıştıracak tamsayı değeridir.
Soda makinesine gelen her alıcı (tüketici) iş parçacığı, soda down()
almak için semafor yöntemini çağırır . Bu, makineden bir soda alacak ve mevcut gazlı içeceklerin sayısını 1 azaltacaktır. Eğer mevcut gazlı içecekler varsa, kod, down()
ifadeyi sorunsuz bir şekilde geçmeye devam edecektir . Gazlı içecek yoksa, iplik burada uyur ve soda tekrar kullanıma sunulduğunda (makinede daha fazla gazlı içecek olduğunda) bilgilendirilmeyi bekler.
Satıcı (üretici) iş parçacığı esasen soda makinesinin boş olmasını bekliyor olacaktı. Satıcı, makineden son soda alındığında bildirim alır (ve bir veya daha fazla tüketici potansiyel olarak gazlı içecekleri çıkarmayı beklemektedir). Satıcı semafor up()
yöntemiyle soda makinesini yeniden stoklayacak , mevcut gazlı içecek sayısı her seferinde artırılacak ve böylece bekleyen tüketici ipleri, daha fazla soda mevcut olduğu konusunda bilgilendirilecek.
wait()
Ve signal()
bir senkronizasyon değişkenin yöntemleri içinde gizli olabilir eğilimindedir down()
ve up()
semafor operasyonlar.
Kesinlikle iki seçenek arasında örtüşme var. Bir semaforun veya bir koşul değişkeninin (veya koşul değişkenleri kümesinin) amaçlarınıza hizmet edebileceği birçok senaryo vardır. Hem semaforlar hem de koşul değişkenleri, karşılıklı dışlamayı sürdürmek için kullandıkları bir kilit nesnesiyle ilişkilendirilir, ancak daha sonra, iş parçacığı yürütmeyi senkronize etmek için kilidin üstünde ekstra işlevsellik sağlarlar. Durumunuz için hangisinin en mantıklı olduğunu bulmak çoğunlukla size bağlıdır.
Bu ille de en teknik açıklama değil, ama benim kafamda bu mantıklı geliyor.
Kaputun altında ne olduğunu ortaya çıkaralım.
Koşullu değişken esasen bir bekleme kuyruğudur , engelleme-bekleme ve uyandırma işlemlerini destekler, yani bekleme kuyruğuna bir iş parçacığı koyabilir ve durumunu BLOK olarak ayarlayabilir ve ondan bir iş parçacığı çıkarabilir ve durumunu HAZIR olarak ayarlayabilirsiniz.
Koşullu bir değişken kullanmak için iki öğenin daha gerekli olduğunu unutmayın:
Protokol daha sonra,
Semafor aslında bir sayaç + bir muteks + bir bekleme kuyruğudur. Ve dış bağımlılıklar olmadan olduğu gibi kullanılabilir. Bunu bir muteks veya koşullu değişken olarak kullanabilirsiniz.
Bu nedenle, semafor, koşullu değişkenden daha karmaşık bir yapı olarak ele alınabilirken, ikincisi daha hafif ve esnektir.
Semaforlar değişkenlere özel erişim uygulamak için kullanılabilir, ancak senkronizasyon için kullanılması amaçlanmıştır. Öte yandan, muteksler, kesinlikle karşılıklı dışlama ile ilgili olan bir semantiğe sahiptir: yalnızca kaynağı kilitleyen işlemin kilidini açmasına izin verilir.
Maalesef mutekslerle senkronizasyon uygulayamazsınız, bu yüzden koşul değişkenlerimiz var. Ayrıca, koşul değişkenleriyle, yayın kilidini açmayı kullanarak aynı anda tüm bekleyen iş parçacıklarının kilidini açabileceğinizi unutmayın. Bu semaforlarla yapılamaz.
semafor ve koşul değişkenleri çok benzerdir ve çoğunlukla aynı amaçlar için kullanılır. Ancak, birini tercih edilebilir kılan küçük farklılıklar vardır. Örneğin, bariyer senkronizasyonunu uygulamak için bir semafor kullanamazsınız, ancak bir koşul değişkeni idealdir.
Engel senkronizasyonu, tüm iş parçacıklarınızın, herkesin iş parçacığı işlevinde belirli bir kısma gelene kadar beklemesini istediğiniz zamandır. bu, başlangıçta bu bariyere ulaştığında her bir diş tarafından azaltılan toplam ipliklerin değeri olan statik bir değişkene sahip olarak uygulanabilir. bu, sonuncusu gelene kadar her bir iş parçacığının uyumasını istediğimiz anlamına gelir; bir semafor tam tersini yapar! bir semafor ile, her iş parçacığı çalışmaya devam eder ve son evre (semafor değerini 0'a ayarlayacak) uyku moduna geçer.
Öte yandan bir koşul değişkeni idealdir. her iplik bariyere ulaştığında statik sayacımızın sıfır olup olmadığını kontrol ederiz. değilse, iş parçacığını durum değişkeni wait işlevi ile uykuya ayarlarız. son iş parçacığı engele ulaştığında, sayaç değeri sıfıra düşürülür ve bu son iş parçacığı, diğer tüm iş parçacıkları uyandıracak koşul değişkeni sinyal fonksiyonunu çağırır!
Durum değişkenlerini monitör senkronizasyonu altında dosyaladım. Genelde semaforları ve monitörleri iki farklı senkronizasyon stili olarak gördüm. İkisi arasında ne kadar durum verisinin doğası gereği tutulduğu ve kodu nasıl modellemek istediğiniz açısından farklılıklar vardır - ancak gerçekten biri tarafından çözülebilecek ancak diğeri tarafından çözülebilecek herhangi bir sorun yoktur.
İzleme biçimine doğru kodlama eğilimindeyim; Çalıştığım çoğu dilde, muteksler, koşul değişkenleri ve bazı destek durumu değişkenleri söz konusudur. Ancak semaforlar da işi yapacaktı.
mutex
Ve conditional variables
devralınmıştır semaphore
.
mutex
, semaphore
iki durum kullanır: 0, 1condition variables
semaphore
Sözdizimsel şeker gibiler