2012-10-04 24 views
7

Bu program iki farklı iş parçacığı yürütür ve bana "yarış "ın kazananının kim olduğunu söyleyin.Dekker'ın algoritma karmaşasının değişkeni

Beklenmedik bir şekilde bazen BOTH iş parçacığı "kazanır" (birini ya da kazanacak birini beklemedim). Bu beklenen davranış ve neden? Açıkçası burada temel bir şey eksik.

class Program 
{ 
    public volatile static int a = 0; 
    public volatile static int b = 0; 

    public static void Main() 
    { 
     for(int i = 0; i < 1000; i++) 
     { 
      a = 0; 
      b = 0; 

      Parallel.Invoke(delegate { a = 1; if (b == 0) Console.WriteLine("A wins"); }, 
          delegate { b = 1; if (a == 0) Console.WriteLine("B wins"); }); 

      Console.WriteLine(System.Environment.NewLine); 

      Thread.Sleep(500); 
     } 
    } 
} 

Sonuçlar:

A wins 

B wins 

A wins 
B wins 

A wins 

... 
+0

Uygulamayı "Paralel" ten zayıf eski 'Thread' olarak değiştirirken, işe yarayacak gibi görünüyor. (Nedenini henüz bilmiyorsunuz.) –

+0

@LB: İlginç, büyük olasılıkla, iş parçacıklarının aynı işlemci üzerinde çalışmasıdır. çekirdek? –

+0

ayarı "TaskCreationOptions.LongRunning" ayarı da düzgün çalışmasını sağlıyor. –

cevap

3

Sen uçucu yanlış kullanıyoruz:

uçucu değişkenleri deklare yeterli değil, her yerde bunları yazmak, sen de Thread.VolatileRead(ref myVar)/Thread.VolatileWrite(ref myVar)

, uçucu kullanma/okuma emin olmak gerekir NOT NOT: Doğru şekilde kullanılsa bile okuma/yazma emrini (farklı konulardan) sağlar. Konuyla ilgili bilgi için SO'ya göz atın. DÜZENLEME: Bir x86 tek çekirdekli makinede it seems to do

Sadece lock deyimi kullanabilirsiniz, ancak bu işin sonuna kadar almak istiyorsanız, o zaman tekrar this free e-book

okuma okuma, anlama salık Ekler:
Sadece .NET 4'teki Parallel sınıfına göz attım ve volatile anahtar sözcüğü kullanılmadı.
Ayrıca, herhangi bir sebepten dolayı döngü yapmadan önce Action<T> dizisini kopyalayabilirler, ancak bunun sizi etkilediğinden şüpheliyim.

+0

+1. Konu Kullanılıyor.VolatileRead (ref myVar) vb. Aslında beklenen davranışı verir. Tahminlerim (ve ilk etapta görmek istediğim) değişkenleri değişken olarak bildirmemenin (doğru bellek engellerini takmama) sonuçlarının, bir şekilde rahat bir bellek modeline iyi bir örnek verdiğidir. Bu konuda ayrıntılı düşünmek istiyorsanız kendinizi özgür hissedin. Bu durumun gerçekleştiğine dair daha detaylı bir açıklama olmasa bile, bunu kabul olarak işaretleyeceğim. Teşekkürler! –

+0

@JK. * detaylı * açıklama için ücretsiz e-kitabı okuyun (ancak kendinizi güçlendirin!). –

+0

E-kitap okuyorum. Anlayışımdan VolatileRead bir MemoryBarrier ekler. Bununla birlikte, bu, ikinci ipliğin, ilk ipliğin yazdığı "taze" değeri okuyabileceğini garanti etmez. Yani, bu çalışma olsa bile, teorik olarak (en azından VolatileRead ve VolatieWrite yöntemlerini kullanarak) olmamalı olduğunu düşünüyorum. – Petrakeas

1

iki kazanın da paralel olarak yürütmek zaman.

Belgelerden (http://msdn.microsoft.com/en-us/library/system.threading.tasks.parallel.invoke.aspx): Sağlanan her eylemi muhtemelen paralelinde yürütür.

+0

+1 iyi yakalama! – Gabber

+3

Bu hala tuhaf. a ve b uçucudur ve diğer görevdeki değeri kontrol etmeden önce güncellenir. Yani, b == 1 olup olmadığını kontrol ettiği anda, en az 1 olmalıdır ve tam tersi, bu yüzden mantıksal olarak en fazla birinin kazanabileceği görülmektedir. – GolezTrol

+0

@GolezTrol bu mantıklı olurdu, ancak uçucu olarak ilan edilmelerine rağmen, şu şekilde kullanılmazlar: Volatile kullanılmadan set/set.Read/Volatile.Write –