.NET: Arka plan iş parçacığı sinyali ana iş parçacığı nasıl kullanılabilir? kalmadan


10

ThreadA sinyal ThreadB bazı olay olması uygun teknik, nedir ThreadB bir olay gerçekleşmesi için bekleyen bloke oturmak? Paylaşılan bir Listeyi dolduracak bir arka plan iş parçacığım var <T>. Asılsız olarak "ana" iş parçacığı tarafından alınacak veri olduğu sinyalini bulmaya çalışıyorum.


i bir EventWaitHandle nesneyle bir etkinlik ayarlama kabul ama benim ana iş parçacığı bir Event.WaitOne oturan olamaz(). i bir temsilci geri arama sahip kabul


ancak a) i temsilci işi ana iş parçacığı istemiyorum: iplik fazla şeyler ekleyerek işe geri almak gerekiyor - bunu istemiyoruz Temsilci yürütürken bekler ve b) temsilci ana iş parçacığı üzerinde ayarlanmış olması gerekir, ancak bir UI çalıştırmıyorum, Denetim yok. Delegeyi karşı karşılayın. i kabul


basitçe (zamanlayıcı Senkronize iplik erişimli) sıfır aralık System.Windows.Forms.Timer başlatan bir temsilci geri arama var. o

Timer.Enabled = true;

çağırır ama bu kesmek gibi görünüyor gibi bu şekilde iplik sadece sıkışmış gerekmektedir.

Eski günlerde, nesnem gizli bir pencere oluşturmuş ve iş parçacığı bu gizli pencerelere HWND mesajlarını göndermişti. Gizli bir kontrol oluşturmayı düşündüm, ama yapamayacağımı topladım. Ayrıca, UI'm yok: Nesnem bir web sunucusunda, hizmette veya konsolda oluşturulmuş olabilir, grafiksel bir denetimin görünmesini istemiyorum - ne de System.Windows'daki bağımlılığı derlemek istiyorum. Formlar.


benim nesnesi, bir ISynchronizeInvoke arabirim sahip kabul ama sonra .Invoke (uygulamak gerekir) ve bu benim sorunum.

bloke oturup bir olay gerçekleşmesi için bekleyen iş parçacığı B kalmadan bazı olayın bir sinyal iplik B iplik olması doğru tekniği nedir

?

10

İşte System.ComponentModel.BackgroundWorker sınıfı için bir kod örneği var.

private static BackgroundWorker worker = new BackgroundWorker(); 
    static void Main(string[] args) 
    { 
     worker.DoWork += worker_DoWork; 
     worker.RunWorkerCompleted += worker_RunWorkerCompleted; 
     worker.ProgressChanged += worker_ProgressChanged; 
     worker.WorkerReportsProgress = true; 

     Console.WriteLine("Starting application."); 
     worker.RunWorkerAsync(); 

     Console.ReadKey(); 
    } 

    static void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     Console.WriteLine("Progress."); 
    } 

    static void worker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     Console.WriteLine("Starting doing some work now."); 

     for (int i = 0; i < 5; i++) 
     { 
      Thread.Sleep(1000); 
      worker.ReportProgress(i); 
     } 
    } 

    static void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     Console.WriteLine("Done now."); 
    } 

1

İkinci iş parçacığı başlatmak için bir arka plan çalışmasını kullanır ve verilerin hazır olduğu diğer iş parçacığı bildirmek için ProgressChanged olayını kullanır. Diğer etkinlikler de mevcuttur. THis MSDN article should get you started.

  0

BackgroundWorker sınıf uyumsuz bir TEBLİĞ gönderilen tek şey gibi görünüyor nesneyi oluşturan * iş parçacığı * üzerinde. Dahili olarak asyncOperation.Post() öğesini çağırarak AsyncOperation nesnesini kullanır. 23 eyl. 082008-09-23 21:28:55


1

Tam olarak ne yapmak istediğinize bağlı olarak bunu yapmanın birçok yolu vardır. Bir producer/consumer queue muhtemelen ne istersen. Dişlere mükemmel bir derinlik kazandırmak için, C# 3.0 in a Nutshell numaralı mükemmel kitaptan Threading (çevrimiçi) bölümüne bakın.

  0

Üretici/tüketici modelinde ana iş parçacığı, gerçekleştirilmesi gereken iş birimleri oluşturur. Bir arka plan iş parçacığı beklemek iş bekledi kadar bekler. Bir iş birimi oluşturulduğunda ve etkinlik ayarlandığında. Ana iş parçacığı "tüketici" olduğu için bu işe yaramıyor ve iş için bekleyemez. 23 eyl. 082008-09-23 19:18:57


1

Bir AutoResetEvent (veya ManualResetEvent) kullanabilirsiniz. AutoResetEvent.WaitOne (0, false) kullanırsanız, engellemez.Örneğin:

AutoResetEvent ev = new AutoResetEvent(false); 
... 
if(ev.WaitOne(0, false)) { 
    // event happened 
} 
else { 
// do other stuff 
} 
  0

Etkinliğin işaretli olup olmadığını nasıl kontrol edersiniz? yani ne zaman? 21 kas. 082008-11-21 18:22:21


0

"ana" parçacığı Windows ileti pompadır (GUI) iplik, o zaman bir Forms.Timer kullanarak yoklamak ise - Eğer GUI olması gerekir ne kadar hızlı göre ayar zamanlayıcı aralığını İş parçacığının verilerini iş parçacığına 'bildir'. , CollectionModified özel durumlarından kaçınmak için,erişimini eşzamanlamayı unutmayın.

Bu teknik, gerçek zamanlı bir ticaret uygulamasında tüm piyasa verileri tabanlı GUI güncellemeleri için kullanıyorum ve çok iyi çalışıyor.


3

Birkaç yanıtı burada birleştiriyorum.

İdeal durum, AutoResetEvent gibi bir iş parçacığı güvenli bayrağı kullanır. WaitOne() numaralı telefonu aradığınızda süresiz olarak engellemenize gerek yoktur, aslında zaman aşımı belirtmenize izin veren aşırı yüklenme vardır. Bu aşırı yük, bayrak aralıklı olarak ayarlanmamışsa false değerini döndürür.

Queue, bir üretici/tüketici ilişkisi için daha ideal bir yapıdır, ancak gereksinimleriniz List numaralı telefonu kullanmaya zorlarsa taklit edebilirsiniz. En önemli fark, tüketicilerin eşyalarını çıkarırken koleksiyona erişimlerini engellemesini sağlamak zorunda kalacaksınız; En güvenli şey, tüm elemanları bir diziye kopyalamak için CopyTo yöntemini kullanmaktır, ardından kilidi serbest bırakmanızdır. Elbette, üreticinizin, kilit tutulurken List'u güncellemeye çalışmadığından emin olun.

Bunun nasıl uygulanabileceğini gösteren basit bir C# konsol uygulaması var. Zamanlama aralıkları ile oynarsanız, çeşitli şeylerin meydana gelmesine neden olabilirsiniz; Bu özel konfigürasyonda, tüketicinin ürünler için ürün kontrol etmeden önce birden fazla ürün üretmesini sağlamaya çalışıyordum.

using System; 
using System.Collections.Generic; 
using System.Threading; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     private static object LockObject = new Object(); 

     private static AutoResetEvent _flag; 
     private static Queue<int> _list; 

     static void Main(string[] args) 
     { 
      _list = new Queue<int>(); 
      _flag = new AutoResetEvent(false); 

      ThreadPool.QueueUserWorkItem(ProducerThread); 

      int itemCount = 0; 

      while (itemCount < 10) 
      { 
       if (_flag.WaitOne(0)) 
       { 
        // there was an item 
        lock (LockObject) 
        { 
         Console.WriteLine("Items in queue:"); 
         while (_list.Count > 0) 
         { 
          Console.WriteLine("Found item {0}.", _list.Dequeue()); 
          itemCount++; 
         } 
        } 
       } 
       else 
       { 
        Console.WriteLine("No items in queue."); 
        Thread.Sleep(125); 
       } 
      } 
     } 

     private static void ProducerThread(object state) 
     { 
      Random rng = new Random(); 

      Thread.Sleep(250); 

      for (int i = 0; i < 10; i++) 
      { 
       lock (LockObject) 
       { 
        _list.Enqueue(rng.Next(0, 100)); 
        _flag.Set(); 
        Thread.Sleep(rng.Next(0, 250)); 
       } 
      } 
     } 
    } 
} 

Üreticiyi hiç bir şekilde engellemek istemezseniz, biraz daha zor olur. Bu durumda, üreticiye kendi sınıfını hem özel hem de halka açık bir tampon ve halka açık bir AutoResetEvent ile yapmayı öneriyorum. Üretici varsayılan olarak öğeleri özel tamponda saklayacak, ardından bunları ortak arabelleğe yazmaya çalışacaktır. Tüketici, genel arabellekle çalışırken, üretici nesnesindeki bayrağı sıfırlar. Üreticinin özel tampondan halk arabelleğine taşınmaya çalışmasından önce, bu bayrağı kontrol eder ve yalnızca tüketici üzerinde çalışmadığı zaman öğeleri kopyalar.

  0

Sıra, kullanmak için ilginç bir sınıf gibi görünüyor. Her ne kadar benim durumumda olmasa da, bazen bir kerede, öğeleri tek tek öğeleri deşifre etmek yerine, tüm Listeyi bir kerede ele alabilir. 23 eyl. 082008-09-23 21:31:23


1

BackgroundWorker sınıfı bu durumda yanıttır. BackgroundWorker nesnesini oluşturan iş parçacığı iletisine eşzamansız olarak ileti gönderebilen tek iş parçacıklı yapıdır. Dahili olarak BackgroundWorker, AsyncOperation sınıfını asyncOperation.Post() yöntemini çağırarak kullanır.

  • BackgroundWorker
  • SoundPlayer: .NET çerçevesinde

    this.asyncOperation = AsyncOperationManager.CreateOperation(null); 
    this.asyncOperation.Post(delegateMethod, arg); 
    

    Birkaç diğer sınıflar da AsyncOperation kullanın.LoadAsync()

  • SmtpClient.SendAsync()
  • Ping.SendAsync()
  • WebClient.DownloadDataAsync()
  • WebClient.DownloadFile()
  • WebClient.DownloadFileAsync()
  • WebClient ...
  • PictureBox.LoadAsync()