.NET: पृष्ठभूमि थ्रेड सिग्नल मुख्य थ्रेड डेटा कैसे उपलब्ध है?


10

ThreadA संकेत ThreadB किसी घटना की के लिए उचित तकनीक, क्या है बिना ThreadB अवरुद्ध बैठे हैं जिनमें एक घटना होने की प्रतीक्षा करते?

मेरे पास एक पृष्ठभूमि धागा है जो एक साझा सूची < टी > भर जाएगा। मैं "मुख्य" थ्रेड को अतुल्यकालिक रूप से सिग्नल करने का तरीका ढूंढने की कोशिश कर रहा हूं कि उठाए जाने वाले डेटा उपलब्ध हैं।


मैं एक EventWaitHandle वस्तु के साथ एक घटना की स्थापना पर विचार किया, लेकिन मैं अपने मुख्य थ्रेड एक Event.WaitOne पर बैठे नहीं हो सकता है()।


मैं एक प्रतिनिधि कॉलबैक होने की सोची, परन्तु क) मैं नहीं चाहता कि मुख्य थ्रेड प्रतिनिधि में काम कर रही हैं: धागा अधिक सामग्री जोड़ने वापस काम पर होने की जरूरत है - मैं इसे नहीं करना चाहती प्रतिनिधि प्रतिनिधि निष्पादित करते समय इंतजार कर रहे हैं, और बी) प्रतिनिधि को मुख्य धागे पर मार्शल किया जाना चाहिए, लेकिन मैं यूआई नहीं चला रहा हूं, मेरे पास प्रतिनिधिमंडल के खिलाफ कोई नियंत्रण नहीं है।


मैं माना एक प्रतिनिधि कॉलबैक कि बस एक शून्य अंतराल System.Windows.Forms.Timer (टाइमर समन्वयित किया जाने वाला धागा उपयोग के साथ) शुरू होता है है। इस तरह से धागा केवल के रूप में यह

Timer.Enabled = true;

कॉल, लेकिन यह एक हैक की तरह लगता है अटक जाना चाहिए।

पुराने दिनों में मेरी वस्तु ने एक छिपी हुई खिड़की बनाई होगी और थ्रेड पोस्ट संदेशों को उस छिपी हुई विंडो 'HWND पर पोस्ट किया होगा। मैंने एक छिपी हुई नियंत्रण बनाने पर विचार किया, लेकिन मैं इकट्ठा करता हूं कि आप नहीं कर सकते हैं। किसी भी हैंडल के साथ नियंत्रण पर नियंत्रण रखें। इसके अलावा, मेरे पास कोई यूआई नहीं है: मेरा ऑब्जेक्ट वेब-सर्वर, सेवा या कंसोल पर बनाया जा सकता था, मैं नहीं चाहता कि वहां ग्राफिकल नियंत्रण दिखाई दे - और न ही मैं System.Windows पर निर्भरता संकलित करना चाहता हूं। फार्म।


मैं अपने वस्तु एक ISynchronizeInvoke इंटरफ़ेस का पर्दाफाश होने पर विचार किया है, लेकिन फिर मैं .Invoke (लागू करने के लिए की आवश्यकता होगी), और है कि मेरी समस्या नहीं है।


, धागा कुछ घटना का एक संकेत धागा एक घटना होने का इंतज़ार कर धागा होने अवरुद्ध बैठे हैं जिनमें बिना के लिए उचित तकनीक क्या है?

10

यहां सिस्टम के लिए कोड नमूना है। कॉम्पोनेंट मॉडेल। बैकग्राउंड वर्कर क्लास।

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

यदि आप दूसरे धागे को शुरू करने के लिए पृष्ठभूमि कार्यकर्ता का उपयोग करते हैं और डेटा तैयार होने वाले अन्य थ्रेड को सूचित करने के लिए प्रोग्रेस चेंजेड ईवेंट का उपयोग करते हैं। अन्य घटनाएं भी उपलब्ध हैं। THis MSDN article should get you started

  0

BackgroundWorker वर्ग केवल बात यह है कि अतुल्यकालिक रूप से एक notificati भेजा जा सकता है हो रहा है * थ्रेड * पर जिसने ऑब्जेक्ट बनाया था। आंतरिक रूप से यह AsyncOperation.Post() को कॉल करके AsyncOperation ऑब्जेक्ट का उपयोग करता है। 23 sep. 082008-09-23 21:28:55


1

ऐसा करने के कई तरीके हैं, जो आप करना चाहते हैं उसके आधार पर। एक producer/consumer queue शायद आप जो चाहते हैं। थ्रेड में उत्कृष्ट गहराई से देखने के लिए, उत्कृष्ट पुस्तक C# 3.0 in a Nutshell से Threading (ऑनलाइन उपलब्ध) पर अध्याय देखें।

  0

निर्माता/उपभोक्ता मॉडल में मुख्य धागा काम की इकाइयों को बनाता है जिन्हें करने की आवश्यकता होती है। एक पृष्ठभूमि धागा काम के लिए इंतजार कर बैठता है कतारबद्ध किया जाना चाहिए। जब काम की एक इकाई बनाई जाती है और घटना सेट की जाती है। यह यहां काम नहीं करता है क्योंकि मुख्य धागा "उपभोक्ता" है, और यह काम के लिए इंतजार नहीं कर सकता है। 23 sep. 082008-09-23 19:18:57


1

आप एक ऑटोरेटेवेंट (या मैनुअल रीसेट इवेंट) का उपयोग कर सकते हैं। यदि आप AutoResetEvent.WaitOne (0, false) का उपयोग करते हैं, तो यह अवरुद्ध नहीं होगा।उदाहरण के लिए:

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

आप कैसे जांचते हैं कि घटना संकेतित है या नहीं? यानी कब? 21 nov. 082008-11-21 18:22:21


0

अपने "मुख्य" धागा विंडोज संदेश पंप है (जीयूआई) धागा, तो आप एक Forms.Timer का उपयोग कर मतदान कर सकते हैं - कैसे जल्दी से आप अपने जीयूआई की आवश्यकता के अनुसार धुन टाइमर अंतराल कार्यकर्ता धागे से डेटा थ्रेड 'नोटिस'।

साझा List<> के लिए उपयोग सिंक्रनाइज़ करने के लिए आप foreach उपयोग करने के लिए, CollectionModified अपवाद से बचने के लिए जा रहे हैं याद रखें।

मैं रीयल-टाइम ट्रेडिंग एप्लिकेशन में सभी मार्केट-डेटा-संचालित जीयूआई अपडेट के लिए इस तकनीक का उपयोग करता हूं, और यह बहुत अच्छी तरह से काम करता है।


3

मैं यहां कुछ प्रतिक्रियाएं जोड़ रहा हूं।

आदर्श स्थिति थ्रेड-सुरक्षित ध्वज जैसे AutoResetEvent का उपयोग करती है। WaitOne() पर कॉल करते समय आपको अनिश्चित काल तक अवरुद्ध करने की आवश्यकता नहीं है, वास्तव में इसमें एक अधिभार है जो आपको टाइमआउट निर्दिष्ट करने की अनुमति देता है। अंतराल के दौरान ध्वज सेट नहीं किया गया था, तो यह अधिभार false देता है।

Queue निर्माता/उपभोक्ता संबंध के लिए एक और आदर्श संरचना है, लेकिन यदि आप अपनी आवश्यकताओं को List का उपयोग करने के लिए मजबूर कर रहे हैं तो आप इसकी नकल कर सकते हैं। मुख्य अंतर यह है कि आपको यह सुनिश्चित करना होगा कि आपके उपभोक्ता ताले संग्रह को एक्सेस करते समय संग्रह तक पहुंच जाएं; सबसे सुरक्षित बात यह है कि संभवतः CopyTo विधि का उपयोग सभी तत्वों को सरणी में कॉपी करने के लिए करें, फिर लॉक को छोड़ दें। बेशक, सुनिश्चित करें कि आपका निर्माता लॉक होने पर List को अपडेट करने का प्रयास नहीं करेगा।

यहां एक सरल सी # कंसोल एप्लिकेशन है जो दर्शाता है कि यह कैसे कार्यान्वित किया जा सकता है। यदि आप समय अंतराल के साथ खेलते हैं तो आप विभिन्न चीजें होने का कारण बन सकते हैं; इस विशेष विन्यास में मैं उपभोक्ता वस्तुओं के लिए उपभोक्ता जांच से पहले कई आइटम उत्पन्न करने की कोशिश कर रहा था।

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)); 
       } 
      } 
     } 
    } 
} 

आप बिल्कुल निर्माता ब्लॉक करने के लिए नहीं करना चाहते हैं, यह एक छोटे से अधिक मुश्किल है। इस मामले में, मैं निर्माता को अपनी निजी और सार्वजनिक बफर और सार्वजनिक AutoResetEvent दोनों के साथ अपनी कक्षा बनाने का सुझाव दूंगा। निर्माता निजी बफर में डिफॉल्ट स्टोर आइटमों द्वारा होगा, फिर उन्हें सार्वजनिक बफर में लिखने का प्रयास करें। जब उपभोक्ता सार्वजनिक बफर के साथ काम कर रहा है, तो यह निर्माता ऑब्जेक्ट पर ध्वज रीसेट करता है। निर्माता निजी बफर से सार्वजनिक बफर तक वस्तुओं को स्थानांतरित करने से पहले, यह इस ध्वज की जांच करता है और जब उपभोक्ता इस पर काम नहीं कर रहा है तो केवल आइटम कॉपी करता है।

  0

कतार का उपयोग करने के लिए एक दिलचस्प वर्ग की तरह लगता है। हालांकि मैं इसे अपनी स्थिति में नहीं चाहूंगा क्योंकि कुछ समय बाद उपयोगकर्ता अलग-अलग वस्तुओं को डेक्यू करने के बजाय पूरी सूची को एक साथ संभाल सकता है। 23 sep. 082008-09-23 21:31:23


1

पृष्ठभूमिवर्कर वर्ग इस मामले में उत्तर दे रहा है। यह एकमात्र थ्रेडिंग निर्माण है जो थ्रेड पर बैकग्राउंड वर्कर ऑब्जेक्ट बनाने के लिए संदेशों को अतुल्यकालिक रूप से भेजने में सक्षम है। आंतरिक रूप से BackgroundWorkerasyncOperation.Post() विधि को कॉल करके AsyncOperation कक्षा का उपयोग करता है।

  • BackgroundWorker
  • SoundPlayer:

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

    एक नेट ढांचे में कुछ अन्य वर्गों भी AsyncOperation का उपयोग करें।LoadAsync()

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