2013-05-13 14 views
8

Son zamanlarda Rob Miles'ın (here) çok güzel pdf'sini okurken Threads'a giriyorum. 160. sayfadaki bir örneği vardı (2012, C# pdf) ancak konsola yazmamıştı sadece boş döngüler yaptı.Konuları konsola yazdırmak için iş parçacığı kullandığımda, neden tek bir sonuç üretiyor?

Çok sayıda iş parçacığı üretme özniteliği yazdım. Bu, 1000 öğesinin her birindeki kimliklerini ekrana yazabilen 10 iş parçacığı oluşturur. Bu güzeldi - iş parçacığının birlikte nasıl çalıştığını gösterdi. Sorularım neden başlıyor? Çıktım neden bu kadar karışık? Genellikle aşağıdaki programı çalıştırdığımda, oldukça emin olduğum birden fazla "Thread 3 Finished" satırı alıyorum, sadece bir tanesine sahip olmalıyım.

MSDN'den döngüye bir "lock" ekledim ancak yine de tek bir çıktı üretiyor gibi görünüyor (Aşağıda bir örnek vereceğim). Yerel değişkenler (benim sayma döngü) var, referans olarak değil muhtemelen geçti ve döngü var yaparken sonra ben kilitlemek çalışılmıştır bir int var -

namespace ConsoleApplication1 
    { 
     class Program 
     { 
      static object sync = new object(); 

      static void Main(string[] args) 
      { 
       for (int i = 0; i < 10; i++) 
       { 
        Thread myThread = new Thread(() => DoThis(i)); 
        myThread.Start(); 
       } 
       Console.ReadLine(); 
      } 

      static void DoThis(int s) 
      { 
       lock (sync) // a new addition that hasn't helped 
       { 
        for (long j = 0; j < 10000; j++) 
        { 
         if (j % 1000 == 0) Console.Write(String.Format("{0}.", s)); 
        } 
        Console.WriteLine("\r\nThread {0} Finished", s); 
        Debug.Print("\r\nThread {0} Finished", s); //<-- added to debug 

       } 
      } 
     } 
    } 

Ben olur yaptığımı düşündüm. Sevinç yok. Çıkışı mantıklı yapmak için ne yapmam gerekir? Sorun gidermek için Deubg.Print'i denedim ancak hataları da (aşağıda) var.

Sonunda, daha geniş bir uygulamada iş parçacığı kullanmak istiyorum, ancak burada bulamıyorsam, emin olmak istediğimden emin değilim! sonunda Debug.Print hattından

Örnek Çıktı: (katları unutmayın) ...

Thread 1 Done 
The thread '<No Name>' (0x15cc) has exited with code 0 (0x0). 

Thread 9 Done 
The thread '<No Name>' (0x1d0c) has exited with code 0 (0x0). 

Thread 6 Done 
The thread '<No Name>' (0x2248) has exited with code 0 (0x0). 

Thread 10 Done 
The thread '<No Name>' (0x22bc) has exited with code 0 (0x0). 

Thread 9 Done 
The thread '<No Name>' (0x85c) has exited with code 0 (0x0). 

Thread 9 Done 
The thread '<No Name>' (0x1628) has exited with code 0 (0x0). 

Thread 3 Done 
The thread '<No Name>' (0x2384) has exited with code 0 (0x0). 

Thread 6 Done 

Thread 2 Done 

Thread 4 Done 
The thread '<No Name>' (0x2348) has exited with code 0 (0x0). 
The thread '<No Name>' (0x2420) has exited with code 0 (0x0). 
The thread '<No Name>' (0x1ea8) has exited with code 0 (0x0). 

Ben ettik ne herhangi bir bilgi sunabilir bana bildirin denenmiş.

+1

Sanırım değişkendeki değişkeniniz yakalandı. Geçici bir değişkende saklayın. Ancak, çıktının neden sipariş edilmediğini kastediyorsanız .. Bir iş parçacığının çalıştırılmasının, başlatıldığı sırayla olması garanti edilmez. –

+0

Kesin sipariş hakkında endişelenmeyin ama sanki aynı cevap verildiğinde @MatthewWatson cevap vermiş gibi görünüyor. – Sisyphus

+0

[C# Yakalanan Değişken Döngü Değişkeni] 'nin olası kopyası (http://stackoverflow.com/questions/271440/c-sharp-captured-variable-in-loop) – nawfal

cevap

10

Burada sorun, döngü değişkeninde "değiştirilmiş kapatma" kullanmanızdır.

static void Main(string[] args) 
{ 
    for (int i = 0; i < 10; i++) 
    { 
     int copy = i; // Make a copy of i to prevent the "modified closure" problem. 
     Thread myThread = new Thread(() => DoThis(copy)); 
     myThread.Start(); 
    } 
    Console.ReadLine(); 
} 

bakınız burası için: Bu rağmen

foreach döngüler için sabit olmuştur, for döngüler

bu şekilde Main() değiştirmek düzeltmek için hala bir sorun var (ve hep seveceğim) daha fazla ayrıntı:

Access to Modified Closure

Eric Lippert's Article on Closures

+0

+1 Elbette OP'nin '.Net 4.5' kullanmadığı varsayılıyor. – I4V

+0

Tamam, ben de "i" de kuşkuyla bakıyordum ... Hızlı bir oyun yapalım. – Sisyphus

+2

@ IV4 Kapatma olayı 'for' döngülerinde, sadece foreach döngülerinde değişmedi. Bkz. Http://stackoverflow.com/questions/16264289/captured-closure-loop-variable-in-c-sharp-5-0 –

5

bir döngü içinde konu bulunmuştur kendini Parallel.For kullanarak yerine başlatmayı deneyin:

Parallel.For(0, 10, DoThis); 

Bunu bir parçası olarak ekstra bir argüman (diyelim w) geçmek için gerekli, o zaman bunu yapabilirsiniz:

var w = 4; 
Parallel.For(0, 10, i => DoThis(i, w)); 

Elbette düşünülmesi gereken diğer bir şey, Console nesnesinin özel olmasıdır. Bir iş parçacığından kullanırsanız, kullanmayı deneyen diğer iş parçacıkları tamamlanana kadar engellenir.

Ayrıca, lock (sync), iki iş parçacığının aynı anda işlemlerini yapmasını engeller.

Konularınızın belirli bir sırada yürütülmesinin garanti edilmediğini unutmayın.

+0

Gerçekten hangi siparişe aldırış etmiyorum - kilit benim neyin yanlış gittiğini anlamaya çalışıyordum! Parallel.For (ve daha pek çok başka şey) hiç kullanmadım, bu yüzden hızlı bir okumaya sahip olacaksınız. – Sisyphus

+0

Hala bir değişkene Dothis yöntemine geçebilir miyim? – Sisyphus

+1

'Parallel.For ',' Dothis 'parametresi olarak indeksi (0..9) geçirir -' Dothis ', beklediğiniz türün eşleşmesini bekler, böylece size verdiğim şey' sadece çalışır ' – PhonicUK

İlgili konular