“İş parçacığı açısından güvenli” teriminin anlamı nedir?


367

İki iş parçacığının temel verileri aynı anda değiştiremeyeceği anlamına mı geliyor? Veya bu kod segmentini yürütürken birden fazla iş parçacığı çalıştırıldığında, verilen kod segmentinin öngörülebilir sonuçlarla çalışacağı anlamına mı geliyor?


8
Burada bu konuda ilginç bir tartışma gördüm: blogs.msdn.com/ericlippert/archive/2009/10/19/…
Sebastian

Yanıtlar:


256

Wikipedia'dan:

İplik güvenliği, çok iş parçacıklı programlar bağlamında uygulanabilen bir bilgisayar programlama konseptidir. Bir kod parçası, birden çok iş parçacığı tarafından eşzamanlı yürütme sırasında düzgün çalışıyorsa iş parçacığı için güvenlidir. Özellikle, aynı paylaşılan verilere erişmek için birden fazla iş parçacığı gereksinimini ve herhangi bir zamanda yalnızca bir iş parçacığı tarafından paylaşılan bir veri parçasına erişilme ihtiyacını karşılamalıdır.

İplik güvenliğini sağlamanın birkaç yolu vardır:

Yeniden entrancy:

Kodu bir görev tarafından kısmen yürütülebilecek, başka bir görevle yeniden girilecek ve daha sonra orijinal görevden devam edecek şekilde yazma. Bu, durum bilgisinin statik veya genel değişkenler yerine her görev için yerel değişkenlerde, genellikle yığının üzerinde kaydedilmesini gerektirir.

Karşılıklı dışlama:

Paylaşılan verilere erişim, aynı anda yalnızca bir iş parçacığının paylaşılan verileri okumasını veya yazmasını sağlayan mekanizmalar kullanılarak serileştirilir. Bir kod parçasının birden çok paylaşılan veri parçasına erişmesi durumunda çok dikkatli olunmalıdır; sorunlar arasında yarış koşulları, kilitlenmeler, canlı kilitler, açlık ve birçok işletim sistemi ders kitabında sayılan diğer çeşitli hastalıklar sayılabilir.

Yerel iş parçacığı deposu:

Değişkenler yerelleştirilir, böylece her iş parçacığının kendi özel kopyası olur. Bu değişkenler, alt rutin ve diğer kod sınırları boyunca değerlerini korur ve bunlara erişen kod yeniden girmiş olsa bile, her iş parçacığında yerel oldukları için iş parçacığı açısından güvenlidir.

Atomik işlemler:

Paylaşılan verilere, diğer iş parçacıkları tarafından kesilemeyen atomik işlemler kullanılarak erişilir. Bu genellikle bir çalışma zamanı kitaplığında bulunabilecek özel makine dili yönergelerinin kullanılmasını gerektirir. İşlemler atomik olduğu için, paylaşılan iş parçacığı ne olursa olsun, paylaşılan veriler her zaman geçerli bir durumda tutulur. Atomik işlemler birçok iplik kilitleme mekanizmasının temelini oluşturur.

daha fazla oku:

http://en.wikipedia.org/wiki/Thread_safety



4
Bu bağlantı teknik olarak birkaç kritik noktayı kaçırmaktadır. Söz konusu paylaşılan bellek değiştirilebilir olmalı (Salt okunur bellek iş parçacığı güvensiz olamaz) ve birden çok iş parçacığı, a) belleğin tutarsız olduğu bellekte birden çok yazma işlemi gerçekleştirmelidir (yanlış) ve b) bellek tutarsızken diğer evrelerin bu evreyi kesmesine izin ver.
Charles Bretana

20
Google arandığında ilk sonuç wiki olduğunda, burada gereksiz hale getirmenin bir anlamı yoktur.
Ranvir

Ne demek "bir işleve erişen kod"? Yürütülen işlev koddur, değil mi?
Koray Tugay

82

İş parçacığı için güvenli kod, aynı anda birçok iş parçacığı yürütse bile çalışacak koddur.

http://mindprod.com/jgloss/threadsafe.html


34
Aynı süreç içinde!
Ali Afshar

Gerçekten, aynı süreçte :)
Marek Blotny

4
"Haftalarca istikrarlı bir şekilde çalışacak kod yazmak aşırı paranoya gerektirir." Bu benim sevdiğim bir alıntı :)
Jim T

5
Yaa! bu cevap sadece soruyu yeniden ifade eder! --- Ve neden sadece aynı süreç içinde ??? Birden çok iş parçacığı farklı işlemlerden yürüttüğünde kod başarısız olursa, tartışmalı olarak, ("paylaşılan bellek" bir disk dosyasında olabilir), iş parçacığı güvenli DEĞİLDİR !!
Charles Bretana

1
@ mg30rg. Belki de karışıklık, bir şekilde bir kod bloğunun birden çok işlem tarafından yürütüldüğünü, ancak işlem başına yalnızca bir iş parçacığının yürütüldüğünü, bunun bir şekilde yine de çok iş parçacıklı bir senaryo değil, "Tek iş parçacıklı" bir senaryo olduğunu düşünmesinin sonucudur. . Bu fikir bile yanlış değil. Bu sadece yanlış tanımdır. Açıkçası, çoklu süreçler genellikle aynı iş parçacığında senkronize bir şekilde yürütülmez, (tasarım ile süreçlerin birbiriyle koordineli olduğu ve işletim sisteminin süreçler arasında iş parçacıkları paylaştığı nadir senaryolar hariç)
Charles Bretana

50

Daha bilgilendirici bir soru, kodun iş parçacığını güvenli hale getirmeyen şeydir ve cevap, doğru olması gereken dört koşulun olmasıdır ... Aşağıdaki kodu düşünün (ve makine dili çevirisi)

totalRequests = totalRequests + 1
MOV EAX, [totalRequests]   // load memory for tot Requests into register
INC EAX                    // update register
MOV [totalRequests], EAX   // store updated value back to memory
  1. İlk koşul, birden fazla iş parçacığından erişilebilen bellek konumları olmasıdır. Tipik olarak, bu konumlar global / statik değişkenlerdir veya global / statik değişkenlerden yığın belleğe erişilebilir. Her iş parçacığı, işlev / yöntem kapsamı yerel değişkenler için kendi yığın çerçevesini alır, bu nedenle bu yerel işlev / yöntem değişkenleri olan otoh (yığın üzerinde olan) yalnızca bu yığının sahibi olan iş parçacığından erişilebilir.
  2. İkinci koşul, programın düzgün çalışması için doğru veya geçerli olması gereken bu paylaşılan bellek konumlarıyla ilişkili bir özellik (genellikle değişmez olarak adlandırılır ) olmasıdır. Yukarıdaki örnekte, özellik " totalRequests değerinin herhangi bir iş parçacığının artış ifadesinin herhangi bir bölümünü yürütme sayısını tam olarak temsil etmesi gerektiğidir ". Genellikle, bu değişmez özelliğin, güncelleştirmenin doğru olması için bir güncelleştirme gerçekleşmeden önce true değerine sahip olması gerekir (bu durumda totalRequests doğru sayımı tutmalıdır).
  3. Üçüncü koşul, değişmez özelliğin, gerçek güncelleştirmenin bir kısmı sırasında TUTMAMASIdır. (İşlemenin bir kısmı sırasında geçici olarak geçersiz veya yanlış). Güncellenmiş değeri saklanır zaman, totalRequests vermez kadar bu özel durumda, zaman totalRequests olarak getirildiğinden, değil değişmeyen tatmin.
  4. Bir yarış gerçekleşmesi için gerçekleşmelidir dördüncü ve son durum (ve dolayısıyla kod için DEĞİL olmak "iş parçacığı güvenli") Başka bir iş parçacığı paylaşılan hafızayı erişmek mümkün gerektiğidir ederken değişmez böylece neden bozuldu tutarsız veya yanlış davranış.

6
Bu sadece veri yarışları olarak bilinenleri kapsar ve elbette önemlidir. Yine de, kodun iş parçacığı için güvenli olamamasının başka yolları da vardır - örneğin, kilitlenmelere yol açabilecek kötü kilitleme. Bir Java iş parçacığında bir yerde System.exit () çağırmak gibi basit bir şey bile bu kod iş parçacığı güvenli değil yapar.
Ingo

2
Sanırım bir dereceye kadar bu anlambilimdir, ancak bir kilitlenmeye neden olabilecek kötü kilitleme kodunun kodu güvensiz hale getirmediğini iddia ederim. İlk olarak, yukarıda açıklandığı gibi bir yarış durumu mümkün olmadığı sürece kodu ilk etapta kilitlemeye gerek yoktur. Sonra, kilitleme kodunu bir kilitlenmeye neden olacak şekilde yazarsanız, bu iş parçacığı güvensiz değildir, sadece kötü koddur.
Charles Bretana

1
Ancak kilitlenmenin tek iş parçacıklı çalıştırıldığında meydana gelmeyeceğini unutmayın, bu nedenle çoğumuz için bu kesinlikle "güvenli değil" sezgisel anlamının altına düşecektir.
Jon Coombs

Tabii ki çok iş parçacıklı çalıştırmıyorsanız kilitlenmeler gerçekleşemez, ancak bu, bir makinede çalıştırıyorsanız ağ sorunlarının meydana gelemeyeceğini söylemek gibidir. Programcı, kodu güncelleştirmeyi tamamlamadan önce kritik kod satırlarından çıkacak ve diğer bazı alt yordamdaki değişkeni değiştirecek şekilde yazarsa, tek iş parçacıklı da olabilir.
Charles Bretana

34

Brian Goetz'in Uygulamadaki Java Eşzamanlılığı'ndaki tanımını, kapsamlı olması nedeniyle beğendim

"Bir sınıf, bu iş parçacıklarının çalışma zamanı ortamı tarafından yürütülmesinin planlanması veya serpiştirilmesinden bağımsız olarak ve çağıran kodun hiçbir ek senkronizasyonu veya başka bir koordinasyonu olmaksızın, birden çok iş parçacığından erişildiğinde doğru davranıyorsa iş parçacığı açısından güvenlidir. "


Bu tanım eksiktir ve spesifik değildir ve kesinlikle kapsamlı değildir. Kaç kez güvenli bir şekilde çalışmalı, Sadece bir kez? on kere? her zaman? Zamanın% 80'i? ve onu "Güvensiz" yapan şeyleri belirtmez. Güvenli bir şekilde çalışmazsa, ancak başarısızlık sıfır hatasına bölündüğünden kaynaklanıyorsa, iş parçacığı "Güvenli değil" midir?
Charles Bretana

Bir dahaki sefere daha sivil olun ve belki tartışabiliriz. Bu Reddit değil ve kaba insanlarla konuşma havasında değilim.
Buu Nguyen

Başkasının tanımına ilişkin yorumları kendinize hakaret olarak yorumlamanız anlatıyor. Duygusal tepki vermeden önce maddeyi okumanız ve anlamanız gerekir. Yorumum hakkında uncivil bir şey yok. Tanımın anlamı hakkında bir noktaya değinmiştim. Konuyu göstermek için kullandığım örnekler sizi rahatsız ettiyse özür dilerim.
Charles Bretana

28

Diğerlerinin de işaret ettiği gibi, iş parçacığı güvenliği, aynı anda birden fazla iş parçacığı tarafından kullanılıyorsa, bir kod parçasının hatasız çalışacağı anlamına gelir.

Bunun bazen bir maliyet, bilgisayar zamanı ve daha karmaşık kodlama ile geldiğinin farkında olmakta fayda var, bu yüzden her zaman arzu edilmez. Bir sınıf yalnızca bir iş parçacığında güvenle kullanılabilirse, bunu yapmak daha iyi olabilir.

Örneğin, Java'nın neredeyse eşdeğer iki sınıfı vardır StringBufferve StringBuilder. Fark, StringBufferiş parçacığı açısından güvenli olmasıdır, bu nedenle a'nın tek bir örneği StringBufferaynı anda birden çok iş parçacığı tarafından kullanılabilir. StringBuilderiş parçacığı için güvenli değildir ve Dize yalnızca bir iş parçacığı tarafından oluşturulduğunda bu durumlar için (büyük çoğunluk) daha yüksek performanslı bir yedek olarak tasarlanmıştır.


22

İş parçacığı güvenli kodu, farklı iş parçacıkları tarafından aynı anda girilse bile belirtilen şekilde çalışır. Bu genellikle, kesintisiz olarak çalışması gereken dahili veri yapılarının veya işlemlerin aynı anda farklı değişikliklere karşı korunduğu anlamına gelir.


21

Bunu anlamanın daha kolay bir yolu, kodun iş parçacığı açısından güvenli olmasını sağlamayan şeydir. Dişli bir uygulamanın istenmeyen davranışa sahip olmasını sağlayacak iki ana sorun vardır.

  • Paylaşılan değişkene kilitlemeden erişme
    Bu değişken, işlev yürütülürken başka bir iş parçacığı tarafından değiştirilebilir. Fonksiyonunuzun davranışlarından emin olmak için bir kilitleme mekanizması ile önlemek istiyorsunuz. Genel kural, kilidi mümkün olan en kısa süre tutmaktır.

  • Paylaşılan değişkene karşılıklı bağımlılığın neden olduğu kilitlenme
    İki paylaşılan değişken A ve B'ye sahipseniz. Bir işlevde önce A'yı sonra da B'yi kilitlersiniz. Başka bir işlevde B'yi kilitlemeye başlarsınız ve bir süre sonra A'yı kilitlersiniz. Bu ikinci fonksiyon A'nın kilidinin açılmasını bekleyeceği zaman, birinci fonksiyonun B'nin açılmasını bekleyeceği potansiyel bir kilitlenme. Bu sorun muhtemelen geliştirme ortamınızda ve zaman zaman ortaya çıkmayacaktır. Bundan kaçınmak için, tüm kilitler her zaman aynı sırada olmalıdır.


9

Evet ve hayır.

İş parçacığı güvenliği, paylaşılan verilerinize aynı anda yalnızca bir iş parçacığıyla erişildiğinden emin olmaktan biraz daha fazlasıdır. Paylaşılan verilere sıralı erişim sağlamanız gerekirken aynı zamanda yarış koşullarından , kilitlenmelerden , kilitlenmelerden ve kaynak açlığından kaçınmalısınız .

Birden fazla iş parçacığı çalışırken öngörülemeyen sonuçlar iş parçacığı için güvenli kod gerekli bir koşul değildir , ancak genellikle bir yan üründür. Örneğin, paylaşılan bir kuyruk, bir üretici iş parçacığı ve az sayıda tüketici iş parçacığıyla oluşturulmuş bir üretici-tüketici programınız olabilir ve veri akışı mükemmel bir şekilde tahmin edilebilir. Daha fazla tüketici tanıtmaya başlarsanız, daha rastgele görünen sonuçlar görürsünüz.


9

Temel olarak, çok iş parçacıklı bir ortamda birçok şey yanlış gidebilir (talimatlar yeniden sıralama, kısmen inşa edilmiş nesneler, CPU düzeyinde önbellekleme nedeniyle farklı iş parçacıklarında farklı değerlere sahip aynı değişken vb.).

Uygulamada Java Concurrency tarafından verilen tanımı beğendim :

Bir [kod kısmı], bu iş parçacıklarının çalışma ortamı tarafından yürütülmesinin planlanması veya serpiştirilmesinden bağımsız olarak ve iş parçasının parçası üzerinde ek bir senkronizasyon veya başka bir koordinasyon olmaksızın, birden çok iş parçacığından erişildiğinde doğru davranırsa iş parçacığı için güvenlidir. çağrı kodu.

By doğru onların özelliklerine uygun olarak bu programın davranır demek.

Onaylanmış örnek

Bir sayaç uyguladığınızı düşünün. Aşağıdaki durumlarda doğru davrandığını söyleyebilirsiniz:

  • counter.next() daha önce döndürülmüş bir değeri asla döndürmez (basitlik için taşma vb. varsaymayız)
  • 0 ile mevcut değer arasındaki tüm değerler bir aşamada döndürülür (hiçbir değer atlanmaz)

Bir iş parçacığı güvenli sayacı, aynı anda kaç iş parçacığına eriştiğine bakılmaksızın bu kurallara göre davranır (normalde naif bir uygulama söz konusu olmaz).

Not: Programcılar üzerinde çapraz gönderi


8

Basitçe - çok sayıda iş parçacığı bu kodu aynı anda yürütüyorsa kod düzgün çalışır.


5

İplik güvenliğini determinizmle karıştırmayın. İş parçacığı için güvenli kod da deterministik olmayabilir. İş parçacığı koduyla ilgili sorunları hata ayıklamanın zorluğu göz önüne alındığında, bu muhtemelen normal durumdur. :-)

İş parçacığı güvenliği, bir iş parçacığı paylaşılan verileri değiştirirken veya okurken, başka hiçbir iş parçacığının veri değiştirecek şekilde ona erişememesini sağlar. Kodunuz doğruluk için belirli bir yürütme sırasına bağlıysa, bunu sağlamak için iş parçacığı güvenliği için gerekli olanların ötesinde başka senkronizasyon mekanizmalarına ihtiyacınız vardır.


5

Diğer iyi cevapların üstüne biraz daha bilgi eklemek istiyorum.

İş parçacığı güvenliği, birden fazla iş parçacığının, bellek tutarsızlığı hataları olmadan aynı nesneye veri yazıp okuyabileceğini gösterir. Çok iş parçacıklı programda, iş parçacığı için güvenli bir program paylaşılan verilerde yan etkilere neden olmaz .

Daha fazla ayrıntı için bu SE sorusuna bir göz atın:

Threadsafe ne anlama geliyor?

Güvenli iş parçacığı programı bellek tutarlılığını garanti eder .

Gelişmiş eşzamanlı API üzerindeki Oracle belgeleme sayfasından :

Bellek Tutarlılığı Özellikleri:

Java ™ Dil Spesifikasyonu'nun 17. Bölümünde, paylaşılan değişkenlerin okunması ve yazılması gibi bellek işlemleriyle ilgili önce gerçekleşen ilişki tanımlanmaktadır. Bir iş parçacığı tarafından yazmanın sonuçlarının, yalnızca yazma işlemi okuma işleminden önce gerçekleşirse başka bir iş parçacığı tarafından okunabileceği garanti edilir .

synchronizedVe volatileyapılar yanı sıra Thread.start()ve Thread.join()yöntemleri kutu formu olur-öncesi ilişkilerin.

Alt java.util.concurrentpaketlerdeki ve alt paketlerindeki tüm sınıfların yöntemleri bu garantileri daha yüksek seviyeli senkronizasyona genişletir . Özellikle:

  1. Herhangi bir eşzamanlı koleksiyona bir nesne yerleştirmeden önce bir iş parçacığındaki eylemler, o öğenin başka bir iş parçacığındaki koleksiyondan erişilmesi veya koleksiyondan kaldırılmasından sonraki eylemlerden önce gerçekleşir.
  2. Öncesinde sunulması için dizisindeki Eylemler Runnablebir Executordurum daha önce onun yürütme başlar. Benzer şekilde bir ExecutorService.
  3. FutureSonucun Future.get()başka bir iş parçacığında alınmasının ardından gerçekleşen bir eylemle temsil edilen eşzamansız hesaplama tarafından gerçekleştirilen eylemler .
  4. Başka bir iş parçacığında aynı eşleyici nesnesinde olduğu gibi başarılı bir "edinme" yöntemini izleyen eylemler gibi eşleyici yöntemlerini "serbest bırakmadan" Lock.unlock, Semaphore.release, and CountDownLatch.countDownönceki işlemler Lock.lock, Semaphore.acquire, Condition.await, and CountDownLatch.await.
  5. Nesneleri başarıyla bir şekilde değiştiren her bir iş parçacığı çifti Exchangeriçin exchange(), her iş parçacığından önce gelen eylemler , başka bir iş parçacığında karşılık gelen değiş tokuş () işleminden sonra gerçekleşir.
  6. Aramadan önce Eylemler CyclicBarrier.awaitve Phaser.awaitAdvance(aynı zamanda türevleri gibi) gerçekleşmesi-öncesi eylemleri bariyer etkisiyle gerçekleştirilir ve eylemler bariyer etkisiyle gerçekleştirilen gerçekleşmesi daha önce diğer konuları gelen bekliyor başarılı bir dönüş sonraki eylemler.

4

Diğer cevapları tamamlamak için:

Senkronizasyon yalnızca yönteminizdeki kod iki şeyden birini yaptığında endişe vericidir:

  1. iş parçacığı güvenli olmayan bazı dış kaynaklarla çalışır.
  2. Kalıcı bir nesne veya sınıf alanını okur veya değiştirir

Bu, yönteminizde İÇİNDE tanımlanan değişkenlerin her zaman iş parçacığı güvenli olduğu anlamına gelir. Bir yönteme yapılan her çağrının bu değişkenlerin kendi sürümü vardır. Yöntem başka bir iş parçacığı veya aynı iş parçacığı tarafından çağrılırsa veya yöntem kendisini çağırsa bile (özyineleme), bu değişkenlerin değerleri paylaşılmaz.

İş parçacığı zamanlamasının yuvarlak bobin olacağı garanti edilmez . Bir görev, aynı önceliğe sahip iş parçacıkları pahasına CPU'yu tamamen domuz edebilir. Vicdan sahibi olmak için Thread.yield () yöntemini kullanabilirsiniz. Bir iş parçacığının önceliğini azaltmak için (java içinde) Thread.setPriority (Thread.NORM_PRIORITY-1) öğesini kullanabilirsiniz.

Ayrıca şunlara dikkat edin:

  • bu "iş parçacığı için güvenli" yapıları yineleyen uygulamalarda büyük çalışma zamanı maliyeti (başkaları tarafından zaten belirtilmiştir).
  • Thread.sleep (5000) 'in 5 saniye uyuması beklenir. Ancak, birisi sistem saatini değiştirirse, çok uzun süre uyuyabilir ya da hiç uyuyamayabilirsiniz. İşletim sistemi uyanma zamanını göreceli değil mutlak biçimde kaydeder.

2

Evet ve evet. Verilerin aynı anda birden fazla iş parçacığı tarafından değiştirilmediğini ima eder. Ancak, programınız beklendiği gibi çalışabilir ve temelde olmasa bile iş parçacığı açısından güvenli görünebilir.

Sonuçların öngörülemezliğinin, muhtemelen verilerin beklenenden farklı bir sırada değiştirilmesine neden olan 'yarış koşullarının' bir sonucu olduğunu unutmayın.


2

Bunu örnekle cevaplayalım:

class NonThreadSafe {

    private int counter = 0;

    public boolean countTo10() {
        count = count + 1;
        return (count == 10);
    }

countTo10Yöntem sayaç bir ekler ve sonra sayım Sadece gerçek bir kez dönmelidir 10'a çıktı true döndürür.

Bu, yalnızca bir iş parçacığı kodu çalıştırdığı sürece çalışır. İki iş parçacığı aynı anda kodu çalıştırırsa, çeşitli sorunlar oluşabilir.

Örneğin, sayım 9 olarak başlarsa, bir iş parçacığı saymaya 1 ekleyebilir (10 yapma), ancak ikinci bir iş parçacığı yönteme girebilir ve ilk iş parçacığı 10 Daha sonra her iki iş parçacığı karşılaştırmayı yapar ve sayının 11 olduğunu ve her ikisinin de true değerini döndürmediğini bulur.

Bu nedenle bu kod iş parçacığı için güvenli değildir.

Özünde, tüm çoklu iş parçacığı sorunlarına bu tür bir sorunun çeşitliliği neden olur.

Çözüm, ekleme ve karşılaştırmanın (örneğin, iki ifadeyi bir tür senkronizasyon koduyla çevreleyerek) veya iki işlem gerektirmeyen bir çözüm tasarlayarak ayrılamayacağından emin olmaktır. Böyle bir kod iş parçacığı için güvenli olacaktır.


1

En azından C ++, iş parçacığı güvenli adından bir sürü bırakır ki bir yanlış isim biraz olarak düşünüyorum . İş parçacığı açısından güvenli olması için, kodun genellikle bu konuda proaktif olması gerekir. Genellikle pasif bir kalite değildir.

Bir sınıfın lastik sırtı için güvenli olması için, ek yük sağlayan "ekstra" özelliklere sahip olması gerekir. Bu özellikler, sınıfın uygulanmasının bir parçasıdır ve genel olarak, arabirimden gizlenmiştir. Diğer bir deyişle, farklı iş parçacıkları, herhangi bir farklı iş parçacığıyla eşzamanlı erişim ile çakışmaktan endişe etmeden sınıf üyelerinden herhangi birine erişebilir VE bunu yapmak zorunda kalmadan düz eski normal insan kodlama stilini kullanarak bunu çok tembel bir şekilde yapabilir Zaten çağrılan kodun bağırsaklarına yuvarlanan tüm bu çılgın senkronizasyon şeyleri.

İşte bu yüzden bazı insanlar dahili olarak senkronize edilmiş terimi kullanmayı tercih ediyorlar .

Terminoloji Setleri

Karşılaştığım bu fikirler için üç ana terminoloji seti vardır. İlk ve tarihsel olarak daha popüler (ama daha kötü):

  1. iplik güvenli
  2. güvenli değil

İkincisi (ve daha iyisi):

  1. iplik geçirmez
  2. iplik uyumlu
  3. iş parçacığı

Üçüncüsü:

  1. dahili senkronize
  2. harici senkronize
  3. unsynchronizeable

Benzerlikler

iplik güvenli ~ iplik geçirmez ~ dahili senkronize

Bir örnek dahili olarak senkronize (aka. Evreli veya diş geçirmez ) sistemine bir restoran olduğu bir konak kapıda greets sen ve kendinizi sıraya alınmasını olanak vermez size. Ev sahibi, birden fazla müşteriyle ilgilenmek için restoranın mekanizmasının bir parçasıdır ve partilerinin büyüklüğünü hesaba katmak veya sahip oldukları zaman ne kadar zaman aldıklarını görmek gibi bekleyen müşterilerin oturmalarını optimize etmek için bazı zor hileler kullanabilir. hatta telefonla rezervasyon yaptırmak gibi. Tüm bunlar onunla etkileşim için arabirimin bir parçası olduğu için restoran dahili olarak senkronize edilir.

güvenli değil (ama hoş) ~ dişli uyumlu ~ harici senkronize ~ serbest dişli

Diyelim ki bankaya gidiyorsunuz. Banka anlatıcıları için bir çizgi, yani çekişme var. Bir vahşi değilsiniz, bir kaynak için çekişmenin ortasında yapılacak en iyi şeyin uygar bir varlık gibi kuyruk olmak olduğunu bilirsiniz. Hiç kimse teknik olarak bunu yapmaz. Kendi başınıza yapmak için gerekli sosyal programlamaya sahip olduğunuzu umuyoruz. Bu anlamda banka lobisi dışarıdan senkronize edilir. İplik güvensiz olduğunu söylemeliyiz? Eğer iş parçacığı güvenli , iş parçacığı güvensiz bipolar terminoloji seti ile giderseniz bunun anlamı budur . Çok iyi bir terim seti değil. Daha iyi terminoloji harici olarak senkronize edilir,Banka lobisine birden fazla müşteri tarafından erişilmesi düşmanca değildir, ancak onları da senkronize etme işi yapmaz. Müşteriler bunu kendileri yaparlar.

Buna "serbest iplikli" denir, burada "serbest", "bitlerden arınmış" olduğu gibi - veya bu durumda kilitlenir. Peki, daha doğru bir şekilde, senkronizasyon ilkelleri. Bu, kodun bu ilkeller olmadan birden çok iş parçacığında çalışabileceği anlamına gelmez. Sadece yüklü olarak gelmediği anlamına gelir ve uygun gördüğünüz halde bunları kendiniz yüklemek kodun kullanıcısıdır. Kendi senkronizasyon ilkelerinizi kurmak zor olabilir ve kod hakkında çok düşünmeyi gerektirir, ancak aynı zamanda programın günümüzün hiper iş parçacıklı CPU'larında nasıl çalıştığını özelleştirmenize izin vererek mümkün olan en hızlı programa yol açabilir.

güvenli değil iplik (ve kötü) ~ iplik düşman ~ senkronize edilemez

İplik-düşman bir sistemin günlük benzetmesine bir örnek , bir spor otomobili yanıp sönmeyi ve willy-nilly değiştirme şeritlerini kullanmayı reddeden bazı sarsıntılardır. Sürüş stilleri iplik düşmanca veya senkronize edilemez çünkü onlarla koordine etmek için bir yolunuz yoktur ve bu, aynı şeridin çözünürlük olmadan tartışılmasına ve böylece iki otomobilin herhangi bir protokol olmadan aynı alanı işgal etmeye çalıştığı bir kazaya neden olabilir. bunu önlemek. Bu model daha geniş bir yelpazede anti-sosyal olarak da düşünülebilir, çünkü tercih ederim çünkü konulara daha az spesifiktir ve daha genel olarak birçok programlama alanına uygulanabilir.

Neden güvenli iplik ve ark. kötü bir terminoloji seti

İlk ve en eski terminoloji seti, iplik düşmanlığı ve iplik uyumluluğu arasında daha ince bir ayrım yapamaz . İplik uyumluluğu, iplik güvenliğinden daha pasiftir, ancak bu, eşzamanlı iplik kullanımı için çağrılan kodun güvenli olmadığı anlamına gelmez. Sadece buna izin verecek senkronizasyon konusunda pasif olduğu anlamına gelir, onu dahili uygulamanın bir parçası olarak sağlamak yerine arama koduna bırakır. İş parçacığı ile uyumlu olması, kodun büyük olasılıkla varsayılan olarak nasıl yazılması gerektiğidir, ancak bu, programcılar için büyük bir karışıklık noktası olan kendiliğinden güvenlik gibi sanki yanlış bir şekilde iş parçacığı güvensizliği olarak düşünülür .

NOT: Birçok yazılım el kitabı aslında "iş parçacığı uyumlu" terimini kullanarak "iş parçacığı uyumlu" ifadesini kullanmaktadır. Bazı kaynaklar "iş parçacığı açısından güvenli" bir şey olarak adlandırdığı için, "iş parçacığı açısından güvenli" ve "iş parçacığı için güvenli olmayan" terimlerini bu nedenle kullanıyorum. güvenlik için bazı ekstra standartları (senkronizasyon ilkelleri) karşılamanız gerekip gerekmediği ya da "güvenli" olarak kabul edilmesi düşmanca DEĞİLDİR. Bu yüzden bu terimlerden kaçının ve diğer mühendislerle tehlikeli iletişim kurmaktan kaçınmak için daha akıllı terimleri kullanın.

Hedeflerimizi hatırlatmak

Esasen amacımız kaosu yıkmaktır.

Bunu güvenebileceğimiz deterministik sistemler yaratarak yapıyoruz. Determinizm, paralellik, boru hattı ve yeniden sipariş vermenin fırsat maliyetleri nedeniyle pahalıdır. Maliyetlerimizi düşük tutmak için ihtiyaç duyduğumuz determinizm miktarını en aza indirmeye çalışırken, aynı zamanda ne kadar az determinizmi daha da aşındıracak kararlar vermekten kaçınmaya çalışıyoruz.

İpliklerin senkronizasyonu düzeni artırmak ve kaosu azaltmakla ilgilidir. Bunu yaptığınız seviyeler yukarıda belirtilen terimlere karşılık gelir. En yüksek seviye, bir sistemin her seferinde tamamen öngörülebilir bir şekilde davrandığı anlamına gelir. İkinci seviye, sistemin çağrı kodunun öngörülemezliği güvenilir bir şekilde algılayabileceği kadar iyi davrandığı anlamına gelir. Örneğin, bir koşul değişkeninde sahte bir uyanma veya hazır olmadığı için muteksi kilitlemede başarısızlık. Üçüncü seviye, sistemin kimseyle oynayacak kadar iyi davranmadığı ve kaos meydana gelmeden sadece tek iş parçacıklı çalıştırılabileceği anlamına gelir.


1

Yerine düşünme kodu veya sınıflara iplik güvenli ya da değil, ben bunu düşünmek daha yararlı olduğunu düşünüyorum eylemler evreli olarak. İki eylem, rasgele iş parçacığı bağlamlarından çalıştırıldığında belirtildiği gibi davranırsa iş parçacığı için güvenlidir. Birçok durumda, sınıflar bazı eylem kombinasyonlarını destekleyici güvenli bir şekilde destekleyecek, diğerleri desteklemeyecektir.

Örneğin, dizi listeleri ve karma kümeleri gibi birçok koleksiyon, başlangıçta yalnızca bir iş parçacığı ile erişildiyse ve bir referansın başka herhangi bir iş parçacığı tarafından görülebilmesinden sonra hiçbir zaman değiştirilmemeleri durumunda, herhangi bir kombinasyon tarafından rastgele okunabileceğini garanti eder. parazitsiz ipliklerin.

Daha ilginç bir şekilde, .NET'te orijinal olmayan orijinal olan gibi bazı karma set koleksiyonları, hiçbir öğe kaldırılmadığı sürece ve yalnızca bir iş parçacığının onlara yazması şartıyla, koleksiyonun, güncellemelerin ertelenebileceği ve keyfi sırada gerçekleşebileceği, aksi halde normal davranacağı bir koleksiyona erişiyormuş gibi davranacaktır. 1 numaralı iş parçacığı X ve Y'yi ekler ve # 2 numaralı iş parçacığı Y ve X'i arar ve görürse, # 2 numaralı iş parçacığının Y'nin var olduğunu, ancak X'in olmadığını görür; böyle bir davranışın "iş parçacığı açısından güvenli" olup olmadığı, # 2 iş parçacığının bu olasılıkla başa çıkmaya hazır olup olmadığına bağlı olacaktır.

Son bir not olarak, bazı sınıflar - özellikle iletişim kütüphanelerini bloke etmek - diğer tüm yöntemlere göre diş açmaya karşı güvenli olan, ancak iş parçacığı açısından güvenli diğer yöntemlere sahip olmayan bir "kapalı" veya "İmha" yöntemine sahip olabilir. herbiri. Bir iş parçacığı engelleme okuma isteği gerçekleştirirse ve programın bir kullanıcısı "iptal et" i tıklatırsa, okumayı gerçekleştirmeye çalışan iş parçacığı tarafından yakın bir istek gönderilmesi mümkün olmaz. Bununla birlikte, kapatma / atma isteği, eşzamansız olarak, okuma isteğinin en kısa zamanda iptal edilmesine neden olacak bir bayrak ayarlayabilir. Herhangi bir iş parçacığında kapanma gerçekleştirildiğinde, nesne işe yaramaz hale gelir ve gelecekteki eylemlere yönelik tüm girişimler hemen başarısız olur,


0

En basit deyişle: P Bir kod bloğunda birden fazla iş parçacığı yürütmek güvenliyse, iş parçacığı için güvenlidir *

*şartlar geçerlidir

Koşullar 1 gibi diğer yanıtlarla belirtilir. Üzerinde bir iş parçacığı veya birden çok iş parçacığı çalıştırdığınızda sonuç aynı olmalıdır.

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.