2012-06-19 16 views
5

Olası Çoğalt:
C# Captured Variable In LoopBasit Threading

Ben parçacığı birkaç basit uygulamalar üzerinde çalışıyorum ama bu işe almak gibi olamaz:

class ThreadTest 
{ 
    static Queue<Thread> threadQueue = new Queue<Thread>(); 

    static void Main() 
    { 
     //Create and enqueue threads 
     for (int x = 0; x < 2; x++) 
     { 
      threadQueue.Enqueue(new Thread(() => WriteNumber(x))); 
     } 

     while(threadQueue.Count != 0) 
     { 
      Thread temp = threadQueue.Dequeue(); 
      temp.Start(); 
     } 

     Console.Read(); 
    } 

    static void WriteNumber(int number) 
    { 
     for (int i = 0; i < 1000; i++) 
     { 
      Console.Write(number); 
     } 
    } 
} 

Amaç temel olarak bir sıraya iş parçacığını tek tek eklemek ve sonra sıraya göre tek tek gitmek ve Bir iş parçacığı ve onu yürütmek. Benim for döngüsünde "x < 2" bulunduğundan, yalnızca iki iş parçacığı (WriteNumber (0) çalıştırdığı ve WriteNumber (1) çalıştığı bir yer olmalıdır, yani 1000 0 ile bitmem gerekir. Ekranda 1000 1'ler, iş parçacığının nihayetinde nasıl yürütüldüğüne bağlı olarak değişken sırada.

Sonuç olarak, 2000 2'ler. Geldiğim iki olası çözüm şu şekildedir: Göze çarpan bir şeyi özledim ya da x değişkenini WriteNumber işlevine gönderirken, bir başvuruda bulunarak ve pass-by-value yapmıyorsunuz. iş parçacığı, işlevin ayarlandığı zamanın yerine x'in en son sürümünü kullandığını yürütür. Ancak, değişkenlerimin C# cinsinden varsayılan değere göre aktarıldığı ve parametrenizde 'ref' kelimesini eklediyseniz sadece referans olarak iletildiğim benim anlayışımdı.

+2

Bir iş parçacığı sırası kesinlikle sıra dışı bir fikirdir. – CodesInChaos

+0

içgüdüsel olarak hangi threadpool'un yaptığı bir inandırıcı fikir değildir. bu yüzden threadpool instad kullanın. – DarthVader

+0

Threadpooller genellikle bir görev sınıfı örneği kuyruğuna sahiptir ve eğer takip etmek için rahatsız edilebilirlerse, görevleri reddeden ve yürüten sabit bir iş parçacıkları listesi olabilir. Listelerdeki/sıralardaki mikro işlem hataları genellikle felakete yol açar. Bu konuda birkaç girişimde bulundum - listelerindeki ipler “bitti”, serbest bırak ve dizideki deliği doldurmak için yenilerini seçtiğinde anket yapmaya çalışan büyük kod kodları. Gerçekten dehşet verici ... –

cevap

18

Lambda ifadesinde x yakalanıyorsunuz. Konu başlatılmadan önce x değeri 2 olarak değişir.

for (int x = 0; x < 2; x++) 
{ 
    int copy = x; 
    threadQueue.Enqueue(new Thread(() => WriteNumber(copy))); 
} 

Lambda ifadeleri değişkenleri yakalamak: Sen içinde döngü değeri bir kopyasını yapmak gerekir. değeri değeri tarafından geçirilen WriteNumberolduğunu geçirilen olsa da, evre başlatılır tüm kadar en denir değil - Bu süre içinde x döngü içinde bir kopyasını yaparak 2.

olduğunu döngünün her yineleme alır copy değişkeninin kendi ayrı "örneği" ve'un değeri değişmez ... böylece WriteNumber zamanına göre, her copy değişkeni hala bu yineleme için x'un sahip olduğu değere eşittir.

+0

Büyüleyici, teşekkür ederim! Görünüşe göre lambda ifadeleri üzerinde daha fazla araştırma yapacağım! – Jake

9

x değeri döngüsü tamamlandıktan sonra erişilir ve o zaman da 2 nedeniyle oluşur.

Değişken yakalamayı önlemek için geçici bir değişken kullanmanız gerekir.

for (int x = 0; x < 2; x++) 
{ 
    int tmp = x; 
    threadQueue.Enqueue(new Thread(() => WriteNumber(tmp))); 
}