2012-01-06 30 views
11

İki iş parçacığı arasında iletişim kurmanın en iyi yolunun ne olduğunu merak ediyorum. Rastgele sayı üreten (thread Sender) bir iş parçacığım var ve şimdi oluşturulan rasgele sayıları alacak başka bir iş parçacığı (sınıf Alıcısı) istiyorum. Bu Gönderici geçerli:İş parçacığı, iki iş parçacığı arasındaki iletişim C#

public class Sender 
{ 
    public int GenerateNumber(){ 


     //some code 
     return randomNumber; 
    } 
} 

Afcourse ana işlevi O konuları başlayacağız:

static void Main(string[] args){ 

    Sender _sender=new Sender(); 
    Thread thread1=new Thread(new ThreadStart(_sender.GenerateNumber)); 

} 

Ben, Sen kaynağın çeşit (liste, kuyruk gerekir

+0

Her iki iş parçacığı aynı anda başlatılıyor mu? Gönderici beklerken alıcı ne yapıyor? Gönderen, rastgele bir sayı oluşturduktan sonra ne yapar? – cadrell0

+0

Bu .NET 4 IS? – Yahia

+0

Ana işlevde her iki başlığa da başlayacağım ve iş parçacığı işleyicisi çalışacak ve ardından 3 saniye uyuyacağım. Ayrıca veriyi alacağım ...basiclly thread 'll work kullanıcısı olmayan esc tuşuna basın ... reciever ll alınan konsol numaralarına yazınız. – Avicena00

cevap

2

yardımın takdir vb) gönderen ve alıcı arasında paylaşılır. Ve bu kaynağa erişimi senkronize etmeniz gerekecek, aksi takdirde iş parçacıkları arasında veri aktaramayacaksınız.

19

.NET 4 kullanıyorsanız, daha yüksek düzeyli bir soyutlama kullanmanızı öneririm: Task<TResult>. İlk iş parçacığınız (bir iş parçacığı oluşturmayı veya mevcut bir görev işleme iş parçacığı üzerinde zamanlanmış olabilir) görevi zamanlayabilir ve daha sonra durumun durumunu denetleyebilir, sonuç için vb.

Tek adımlık bir görevden daha fazlasını yapmak istiyorsanız, bir üretici/tüketici sırası kullanmak isteyebilirsiniz - yine, .NET 4, BlockingCollection<T> aracılığıyla bununla yardımcı olur.

+1

I C# derinliğinde okumak zorunda olduğumu biliyordum, bu yüzden bu akşam başlayacağım :) – Avicena00

+1

@AintMeBabe: Dürüst olmak gerekirse, C# derinliklerinde yeni Görev ' 'öğelerine neredeyse hiç dokunmuyor ... MSDN aracılığıyla Görev Paralel Kitaplığı araştırması Blog gönderileri, kitaptan daha acil yarar sağlayabilir. Uzun vadede sizi vazgeçirmeyeceğim değil elbette :) –

+0

Eğer üretici üzerinde herhangi bir kontrole sahip değilsek; Benim bağlamımda, iş parçacığı A (denetimimin altında) bir şey yapar ve bir iş parçacığı oluşturmak için iş parçacığı B'nin beklemesi gerekir; B iş parçacığı bir kitaplık tarafından oluşturulur. Etkinliği dinliyorum. Olay dinleyicisi (B iş parçacığında), A iş parçacığını nasıl bildirmeli? ManualResetEvent dışında bir şey düşünemiyorum. .net 4'te daha iyi bir yaklaşım var mı? – Jimmy

0

Yaptığınız tek şey bir iş parçacığında rasgele bir sayı oluşturmaksa, bunun yerine bunu yapan bir iş parçacığı güvenli nesnesi oluşturabilirdim.

lock(syncRoot) 
{ 
    myCurrentRandom = Generate(); 
    return myCurrentRandom; 
} 
+0

iyi bir nokta, bu iş parçacığı gönderici 'll ll birkaç yöntem – Avicena00

6

İşte waitHandle kullanarak olası bir yaklaşım:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Sender _sender = new Sender(); 
     Receiver _receiver = new Receiver(); 

     using (ManualResetEvent waitHandle = new ManualResetEvent(false)) 
     { 
      // have to initialize this variable, otherwise the compiler complains when it is used later 
      int randomNumber = 0; 

      Thread thread1 = new Thread(new ThreadStart(() => 
      { 
       randomNumber = _sender.GenerateNumber(); 

       try 
       { 
        // now that we have the random number, signal the wait handle 
        waitHandle.Set(); 
       } 
       catch (ObjectDisposedException) 
       { 
        // this exception will be thrown if the timeout elapses on the call to waitHandle.WaitOne 
       } 
      })); 

      // begin receiving the random number 
      thread1.Start(); 

      // wait for the random number 
      if (waitHandle.WaitOne(/*optionally pass in a timeout value*/)) 
      { 
       _receiver.TakeRandomNumber(randomNumber); 
      } 
      else 
      { 
       // signal was never received 
       // Note, this code will only execute if a timeout value is specified 
       System.Console.WriteLine("Timeout"); 
      } 
     } 
    } 
} 

public class Sender 
{ 
    public int GenerateNumber() 
    { 
     Thread.Sleep(2000); 

     // http://xkcd.com/221/ 
     int randomNumber = 4; // chosen by fair dice role 

     return randomNumber; 
    } 
} 

public class Receiver 
{ 
    public void TakeRandomNumber(int randomNumber) 
    { 
     // do something 
     System.Console.WriteLine("Received random number: {0}", randomNumber); 
    } 
} 


Sadece içinde Task<TResult> sınıfını kullanarak yukarıdaki örneğe eşdeğer kod olduğunu düşünüyorum sağlamak için benim cevap güncellemek istedim. NET 4, Jon Skeet tarafından cevabında belirtti. Kredi ona işaret ettiği için ona gider. Çok sağol Jon. Henüz bu sınıfı kullanmak için bir nedenim olmadı ve ne kadar kolay kullanıldığını gördüğümde hoş bir sürpriz oldu.

Bu sınıfın kullanılmasıyla kaputun altında kazandığınız performans avantajlarının yanı sıra, Task<TResult> sınıfını kullanarak eşdeğer kod yazmak çok daha kolay görünüyor. Örneğin, yukarıdaki şekilde tekrar yazılabilir Ana yöntemin vücut aşağıda gösterilen: Eğer görev için bir zaman aşımı belirtmek gerek var ve sonsuza kadar beklemek içerik varsa bunu bitirmek için

 Sender _sender = new Sender(); 
     Receiver _receiver = new Receiver(); 

     Task<int> getRandomNumber = Task.Factory.StartNew<int>(_sender.GenerateNumber); 

     // begin receiving the random number 
     getRandomNumber.Start(); 

     // ... perform other tasks 

     // wait for up to 5 seconds for the getRandomNumber task to complete 
     if (getRandomNumber.Wait(5000)) 
     { 
      _receiver.TakeRandomNumber(getRandomNumber.Result); 
     } 
     else 
     { 
      // the getRandomNumber task did not complete within the specified timeout 
      System.Console.WriteLine("Timeout"); 
     } 

, o zaman yazabilirsiniz Bu kullanarak daha az kod: iki iş parçacığı arasında iletişimi sağlamak için

 Sender _sender = new Sender(); 
     Receiver _receiver = new Receiver(); 

     Task<int> getRandomNumber = Task.Factory.StartNew<int>(_sender.GenerateNumber); 

     // begin receiving the random number 
     getRandomNumber.Start(); 

     // ... perform other tasks 

     // accessing the Result property implicitly waits for the task to complete 
     _receiver.TakeRandomNumber(getRandomNumber.Result); 
+0

teşekkür ederim :) teşekkür ederim :) – Avicena00

+0

başparmak yukarıya !!!!!! – Avicena00

+0

@AintMeBabe - .NET 4 kullanıyorsanız, Jon Skeet'in cevabını kontrol etmenizi tavsiye etmeliyim. Aynı görevi "Görev " sınıfını kullanarak çok daha az kod ile yapabileceğiniz görülüyor. –

0

"en iyi" yolu gerçekten tebliğ gerekenleri bağlıdır. Örneğiniz klasik bir üretici/tüketici problemi gibi görünüyor. Senkronize Kuyruk kullanıyorum. Senkronize Koleksiyonlar için MSDN belgelerine göz atın. Bir Queue nesnesi için senkronize sarıcı almak için Queue.Synchronized yöntemini kullanabilirsiniz. Ardından, üretici iş parçacığına Enqueue() öğesini ve tüketici Dequeue() öğesini çağırın.

İlgili konular