"Veri yarışları" ve "yarış durumu" eşzamanlı programlama bağlamında aslında aynı şey midir?


Yanıtlar:


143

Hayır, aynı şey değiller. Birbirlerinin alt kümesi değildirler. Aynı zamanda birbirleri için ne gerekli ne de yeterli koşuldurlar.

Bir veri yarışının tanımı oldukça açıktır ve bu nedenle keşfi otomatikleştirilebilir. Farklı iş parçacıklarından 2 talimat aynı bellek konumuna eriştiğinde, bu erişimlerden en az biri bir yazmadır ve bu erişimler arasında herhangi bir özel sırayı zorunlu kılan herhangi bir senkronizasyon olmadığında bir veri yarışı gerçekleşir .

Bir yarış koşulu anlamsal bir hatadır. Hatalı program davranışına yol açan olayların zamanlamasında veya sıralanmasında ortaya çıkan bir kusurdur. Birçok yarış durumu veri yarışlarından kaynaklanabilir, ancak bu gerekli değildir.

X'in paylaşılan bir değişken olduğu aşağıdaki basit örneği düşünün:

Thread 1    Thread 2

 lock(l)     lock(l)
 x=1         x=2
 unlock(l)   unlock(l)

Bu örnekte, 1. ve 2. evreden x'e yazılanlar kilitler tarafından korunmaktadır, bu nedenle bunlar her zaman, çalışma zamanında kilitlerin alınma sırasına göre uygulanan bir sırayla gerçekleşir. Yani, yazarların atomikliği kırılamaz; Herhangi bir yürütmede iki yazma arasındaki ilişkiden önce her zaman bir olur. Hangi yazının diğerinden önce gerçekleştiğini bilemeyiz.

Yazılar arasında sabit bir sıralama yoktur çünkü kilitler bunu sağlayamaz. Programın doğruluğu tehlikeye atılırsa, diyelim ki x'e iş parçacığı 2'ye yazmanın ardından evre 1'de x'e yazma geliyorsa, teknik olarak veri yarışı olmamasına rağmen bir yarış koşulu var deriz.

Yarış koşullarını tespit etmek veri yarışlarından çok daha kullanışlıdır; ancak bunu başarmak da çok zordur.

Ters örneği oluşturmak da önemsizdir. Bu blog yazısı, basit bir banka işlemi örneğiyle farkı çok iyi açıklıyor.


1
"veri yarışı (...) bu erişimler arasında belirli bir sırayı zorunlu kılan bir senkronizasyon yok." Biraz kafam karıştı Örneğinizde, işlemler her iki sırada da gerçekleşebilir (= 1 sonra = 2 veya tam tersi). Neden bir veri yarışı değil?
josinalvo

6
@josinalvo: Bu, bir veri yarışının teknik tanımının bir ürünüdür. Kilit nokta, iki erişim arasında bir kilit açma ve bir kilit alımı (olası emirlerden biri için) olacaktır. Tanım olarak, bir kilit serbest bırakma ve bir kilit alma, iki erişim arasında bir düzen oluşturur ve bu nedenle veri yarışı yoktur.
Barış Kasıkçı

Senkronizasyon , operasyonlar arasında hiçbir zaman belirli bir düzeni zorunlu kılmadığından, bunu ifade etmenin pek şanslı bir yolu değildir. Öte yandan, JMM, bir veri yarışında bile her okuma işlemi için gözlemlediği belirli bir yazma işlemi olması gerektiğini belirtir. Bu söz etmek açıkça önlemek zor olur daha önce yine hatta JLS tanımı sadece söz yanlış olduğunu ve senkronizasyon düzenine olur-öncesi : onun tanımı gereği, iki eşzamanlı uçucu yazıyor veri yarışı oluşturmaktadır.
Marko Topolnik

@BarisKasikci "bir düzen kurar" ın bana göre gerçek bir anlamı yok. Onlar sadece çakal sözler. Dürüst olmak gerekirse, "veri yarışının" uzaktan kullanışlı bir kavram olduğuna inanmıyorum, çünkü birden fazla iş parçacığı tarafından erişilen her bellek konumu bir "veri yarışında" olarak kabul edilebilir
Noldorin

Serbest bırakma-edinme çiftleri her zaman bir sipariş oluşturur. Genel bir açıklama uzundur, ancak önemsiz bir örnek sinyal bekle çiftidir. @Noldorin "Bir düzen kurar", eşzamanlılık teorisinin (Lamport'un ilişkiden önce olanlarla ilgili ufuk açıcı makalesine bakın) ve dağıtılmış sistemlerin temel bir kavramı olan bir siparişten önce gerçekleşir. Veri yarışları, varlıklarının birçok sorunu ortaya çıkardığı için yararlı bir kavramdır (örneğin, C ++ bellek modeline göre tanımlanmamış anlambilim, Java'da çok karmaşık anlambilim vb.). Bunların tespiti ve ortadan kaldırılması, araştırma ve uygulamada geniş bir literatür oluşturur.
Barış Kasıkçı

20

Wikipedia'ya göre "yarış durumu" terimi, ilk elektronik mantık kapılarının kurulduğu günlerden beri kullanılmaktadır. Java bağlamında, bir yarış koşulu, bir dosya, ağ bağlantısı, bir iş parçacığı havuzundan bir iş parçacığı vb. Gibi herhangi bir kaynakla ilgili olabilir.

"Veri yarışı" terimi, en iyi JLS tarafından tanımlanan özel anlamı için ayrılmıştır .

En ilginç durum, bir veri yarışına çok benzeyen, ancak bu basit örnekte olduğu gibi yine de bir yarış durumu olmayan bir yarış durumudur:

class Race {
  static volatile int i;
  static int uniqueInt() { return i++; }
}

Yana iuçucudur, hiçbir veri ırk yoktur; ancak, programın doğruluğu açısından, iki işlemin atomik olmamasından kaynaklanan bir yarış koşulu vardır: okuma i, yazma i+1. Birden çok iş parçacığı, aynı değeri alabilir uniqueInt.


1
data raceJLS'de gerçekte ne anlama geldiğini açıklayan cevabınıza bir satır ekleyebilir misiniz ?
Geek

@geek "JLS" kelimesi JLS'nin ilgili bölümüne bir hiperlinktir.
Marko Topolnik

@MarkoTopolnik Örnek beni biraz karıştırdı. Lütfen açıklar mısınız: "Değişken olduğum için veri yarışı yok"? Voltility yalnızca görünür olmasını sağladı, ancak yine de: 1) senkronize edilmedi ve birden fazla iş parçacığı aynı anda okuyabilir / yazabilir ve 2) Paylaşılan nihai olmayan alan. veri yarışıdır, yarış durumu değil, değil mi?
aniliitb10

@ aniliitb10 Bağlamlarından koparılmış ikinci el alıntılara güvenmek yerine, cevabımda bağlantı verdiğim JLS 17.4 bölümünü gözden geçirmelisiniz. Uçucu bir değişkene erişim , §17.4.2'de tanımlanan bir senkronizasyon eylemidir.
Marko Topolnik

@ aniliitb10 Oylar veri yarışına neden olmaz, çünkü erişimleri sipariş edilebilir. Yani, sıralarını şu veya bu şekilde gerekçelendirebilir, farklı sonuçlara yol açabilirsiniz. Veri yarışı ile, siparişi anlamanın bir yolu yok. Örneğin, her iş parçacığının i ++ işlemi, yerel olarak önbelleğe alınan ilgili değeri i üzerine gerçekleşebilir. Küresel olarak bu işlemleri (programcının bakış açısından) sipariş etmenin bir yolu yoktur - belirli bir dil bellek modeliniz yoksa.
Xiao-Feng Li

3

Hayır, farklıdırlar ve hiçbiri birinin alt kümesi değildir veya tam tersi.

Yarış koşulu terimi genellikle, paylaşılan bir nihai olmayan alana tüm erişimi koordine etmek için senkronizasyon kullanılmadığında ortaya çıkan ilgili terim veri yarışıyla karıştırılır. Bir iş parçacığı, daha sonra başka bir evre tarafından okunabilecek bir değişken yazdığında veya her iki iş parçacığı da eşitleme kullanmıyorsa, başka bir evre tarafından en son yazılmış olabilecek bir değişkeni okuduğunda, veri yarışını riske atarsınız; Veri yarışlarına sahip kodun Java Bellek Modeli altında kullanışlı tanımlanmış bir semantiği yoktur. Tüm yarış koşulları veri yarışları değildir ve tüm veri yarışları yarış koşulları değildir, ancak her ikisi de eşzamanlı programların tahmin edilemeyen şekillerde başarısız olmasına neden olabilir.

Mükemmel kitaptan alınmıştır - Joshua Bloch & Co. tarafından Java Eşzamanlılığı Uygulaması


Sorunun dilden bağımsız bir etiketi olduğunu unutmayın.
martinkunev

1

TL; DR: Veri yarışı ve yarış durumu arasındaki ayrım, problem formülasyonunun doğasına ve tanımlanmamış davranış ile iyi tanımlanmış ancak belirsiz davranış arasındaki sınırın nereye çekileceğine bağlıdır. Mevcut ayrım gelenekseldir ve en iyi işlemci mimarı ile programlama dili arasındaki arayüzü yansıtır.

1. Anlambilim

Veri yarışı, özellikle aynı hafıza konumuna senkronize edilmemiş, çakışan "hafıza erişimlerini" (veya eylemleri veya işlemleri) ifade eder. Hafıza erişimlerinde çakışma yoksa, işlem sırasının neden olduğu belirsiz davranış hala mevcutsa, bu bir yarış durumudur.

Buradaki "hafıza erişimlerinin" özel bir anlamı olduğunu unutmayın. Ek anlamlar uygulanmadan "saf" bellek yükleme veya depolama eylemlerine atıfta bulunurlar. Örneğin, bir iş parçacığındaki bir bellek deposu, verilerin belleğe yazılmasının ne kadar sürdüğünü (zorunlu olarak) bilmez ve sonunda başka bir iş parçacığına yayılır. Başka bir örnek için, bir bellek aynı iş parçacığı tarafından başka bir konuma başka bir yere depolanmadan önce bir konuma depolanır, (zorunlu olarak) belleğe yazılan ilk verilerin ikincinin önünde olmasını garanti etmez. Sonuç olarak, bu saf bellek erişimlerinin sırası (zorunlu olarak) "gerekçelendirilemez" ve aksi iyi tanımlanmadıkça her şey olabilir.

"Bellek erişimleri", senkronizasyon yoluyla sıralama açısından iyi tanımlandığında, ek anlambilim, bellek erişimlerinin zamanlaması belirsiz olsa bile, sıralarının senkronizasyonlar yoluyla "gerekçelendirilebilmesini" sağlayabilir . Unutmayın, bellek erişimleri arasındaki sıralama gerekçelendirilebilir, ancak bunlar mutlaka belirli değildir, dolayısıyla yarış durumu.

2. Neden fark var?

Ancak sıra yarış durumunda hala belirsizse, neden onu veri yarışından ayırmaya çalışalım? Sebep teorik olmaktan çok pratiktir. Bunun nedeni, programlama dili ile işlemci mimarisi arasındaki arayüzde ayrımın var olmasıdır.

Modern mimaride bir bellek yükleme / depolama talimatı, sıra dışı ardışık düzen, spekülasyon, çok seviyeli önbellek, cpu-ram ara bağlantısı, özellikle çok çekirdekli vb. Nedeniyle genellikle "saf" bellek erişimi olarak uygulanır. Belirsiz zamanlama ve siparişe yol açan birçok faktör vardır. Her bellek talimatı için sipariş vermeyi zorunlu kılmak, özellikle çok çekirdeği destekleyen bir işlemci tasarımında büyük cezalara neden olur. Dolayısıyla, sıralama anlambilimine çeşitli engeller (veya çitler) gibi ek talimatlar verilir.

Veri yarışı, çakışan bellek erişimlerinin sıralanmasına yardımcı olmak için ek sınırlar olmaksızın işlemci talimatının yürütülmesi durumudur. Sonuç sadece belirsiz değil, aynı zamanda muhtemelen çok tuhaftır, örneğin, aynı kelime konumuna farklı diziler tarafından iki yazma, kelimenin her yazma yarısıyla sonuçlanabilir veya yalnızca yerel olarak önbelleğe alınmış değerleri üzerinde çalışabilir. - Bunlar programcının bakış açısından tanımlanmamış davranışlardır. Ancak (genellikle) işlemci mimarının bakış açısından iyi tanımlanmıştır.

Programcılar için bir yol olması gerekir mantığa onların kod yürütülmesine. Veri yarışı, mantıklı olamayacakları bir şeydir, bu nedenle her zaman (normal olarak) kaçınmalıdır. Bu nedenle, yeterince düşük seviyeli dil spesifikasyonları, genellikle veri yarışını tanımlanmamış davranış olarak tanımlar, yarış durumunun iyi tanımlanmış bellek davranışından farklıdır.

3. Dil bellek modelleri

Farklı işlemcilerin farklı bellek erişim davranışları, yani işlemci bellek modeli olabilir. Programcıların her modern işlemcinin bellek modelini incelemesi ve ardından bunlardan yararlanabilecek programlar geliştirmesi garip. Dilin bir bellek modeli tanımlayabilmesi arzu edilir, böylece bu dilin programları her zaman bellek modelinin tanımladığı gibi beklendiği gibi davranır. Java ve C ++ 'nın bellek modellerinin tanımlanmasının nedeni budur. Dil bellek modellerinin farklı işlemci mimarilerinde uygulanmasını sağlamak derleyici / çalıştırma zamanı geliştiricilerinin sorumluluğudur.

Bununla birlikte, bir dil işlemcinin düşük seviyeli davranışını açığa çıkarmak istemiyorsa (ve modern mimarilerin belirli performans avantajlarından ödün vermek istiyorsa), "saf" ayrıntılarını tamamen gizleyen bir bellek modeli tanımlamayı seçebilirler. bellek erişir, ancak tüm bellek işlemleri için sıralama semantiğini uygular. Daha sonra derleyici / çalışma zamanı geliştiricileri, tüm işlemci mimarilerinde her bellek değişkenini geçici olarak ele almayı seçebilir. Bu diller için (iş parçacıkları arasında paylaşılan hafızayı destekleyen), veri yarışları yoktur, ancak tam sıralı tutarlılık diliyle bile yine de yarış koşulları olabilir.

Öte yandan, işlemci bellek modeli daha katı (veya daha az gevşemiş veya daha yüksek düzeyde) olabilir, örneğin, ilk gün işlemcilerinin yaptığı gibi sıralı tutarlılık uygulayarak. Daha sonra tüm bellek işlemleri sıralanır ve işlemcide çalışan herhangi bir dil için veri yarışı olmaz.

4. Sonuç

Orijinal soruya geri dönersek, IMHO veri yarışını özel bir yarış durumu olarak tanımlamakta sorun yoktur ve bir seviyedeki yarış durumu daha yüksek bir seviyede veri yarışı haline gelebilir. Sorun formülasyonunun doğasına ve tanımlanmamış davranış ile iyi tanımlanmış ancak belirsiz davranış arasındaki sınırın nereye çekileceğine bağlıdır. Sadece mevcut kural, dil işlemci arayüzündeki sınırı tanımlar, bunun her zaman olduğu ve olması gerektiği anlamına gelmez; ancak mevcut konvansiyon muhtemelen en iyi işlemci mimarı ile programlama dili arasındaki son teknoloji arayüzü (ve bilgeliği) yansıtı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.