Koşullu Değişken ve Semafor


Yanıtlar:


207

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.


9
Harika cevap, diğer cevaplardan eklemek istiyorum: Semafor, yürütülen iş parçacığı sayısını kontrol etmek için kullanılır. Sabit kaynak seti olacaktır. Bir iş parçacığının aynı sahip olduğu her seferinde kaynak sayısı azalır. Semafor sayısı 0'a ulaştığında, başka hiçbir iş parçacığının kaynağı almasına izin verilmez. İş parçacıkları, kaynak sürümüne sahip diğer iş parçacıkları kadar engellenir. Kısacası, temel fark, kaynağı aynı anda almak için kaç iş parçacığına izin verildiğidir? Mutex - onun BİR. Semafor - DEFINED_COUNT, (semafor sayısı kadar)
berkay

10
Sadece basit bir eğer yerine bu while döngüsünün neden olduğunu açıklamak için: spurios uyandırma denen bir şey . Aktaran Bu wikipedia makale : ; "Bunun nedenlerinden biri, bir sahte uyandırma olduğunu, bir iş parçacığı hiçbir iplik koşulu değişkeni işaret olsa da bekleme durumundan uyandı olabilir"
Vladislavs Burakovs

3
@VladislavsBurakovs İyi nokta! Bence, bir yayının mevcut kaynaklardan daha fazla iş parçacığı uyandırması durumunda da yararlı olduğunu düşünüyorum (örneğin, yayın 3 iş parçacığını uyandırır, ancak kuyrukta yalnızca 2 öğe vardır).
Brent Kod Yazıyor

Keşke sıra dolana kadar cevabınızı oylayabilsem;) Mükemmel Cevap. Bu kod semaforları bulmaya yardımcı olabilir csc.villanova.edu/~mdamian/threads/PC.htm
Mohamad-Jaafar NEHME

3
@VladislavsBurakovs Biraz açıklığa kavuşturmak için, koşulun henüz yeni uyanmış bir iş parçacığı için yanlış olmasının nedeni (sahte bir uyanmaya neden olur), iş parçacığı durumu kontrol etme şansı elde etmeden önce bir bağlam anahtarı olmuş olabilir. yine, başka bir zamanlanmış iş parçacığı bu koşulu yanlış yaptı. Bu sahte bir uyanış için bildiğim bir nedendir, daha fazlası olup olmadığını bilmiyorum.
Maksimum

52

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:

  • bir koşul (tipik olarak bir bayrak veya sayaç kontrol edilerek uygulanır)
  • durumu koruyan bir muteks

Protokol daha sonra,

  1. mutex edinmek
  2. durumu kontrol et
  3. koşul doğruysa muteksi engelle ve serbest bırak, yoksa muteksi serbest bırak

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.


mutex bir koşul değişkeni olarak görülebilir, bunun koşulu tutulmuş olup olmamasıdır.
宏杰 李

18

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.


9

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!


1

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ı.


2
"İzleme formunun" ne olduğunu açıklarsanız bu daha iyi bir cevap olacaktır.
Steven Lu

0

mutexVe conditional variablesdevralınmıştır semaphore.

  • Çünkü mutex, semaphoreiki durum kullanır: 0, 1
  • İçin kullandığı sayaç.condition variablessemaphore

Sözdizimsel şeker gibiler


C ++ std kitaplığında bunların tümü, platforma özel API'ler kullanılarak uygulanan bölge nesneleridir. Kesinlikle bir semafor, sinyallenme sayısının engelini kaldıracaktır, koşul değişkeni birden çok kez sinyallenebilir ancak engellemeyi yalnızca bir kez kaldırabilir. Wair'in bir muteksi parametre olarak almasının nedeni budur.
doron
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.