2011-05-23 10 views
5

मैं सी # पर कतार के साथ कैसे काम करूं? मुझे एक थ्रेड चाहिए जो कतार में डेटा को एनक्यू करेगा & एक और धागा डेटा को कतार से हटा देगा। उन धागे एक साथ चलना चाहिए।विभिन्न धागे में कतार के साथ कैसे काम करें

क्या यह संभव है?

+3

प्रश्न स्पष्ट नहीं है –

उत्तर

0

एक संभावित कार्यान्वयन अलग-अलग पढ़ने और लिखने वाले पॉइंटर्स के साथ एक अंगूठी बफर का उपयोग करना है। प्रत्येक पढ़ने/लिखने के ऑपरेशन पर आप अपने स्थानीय संदर्भ में विपरीत पॉइंटर (थ्रेड सुरक्षित होना चाहिए) की प्रतिलिपि बनाते हैं और फिर बैच किए गए रीड या लिखते हैं।

प्रत्येक पढ़ने या लिखने पर आप सूचक को अद्यतन करते हैं और एक पल्स को पल्स करते हैं।

यदि पढ़ा या लिखने वाला धागा उस स्थान पर जाता है जहां आप उचित पॉइंटर को फिर से पढ़ने से पहले अन्य धागे की घटनाओं पर प्रतीक्षा करने के लिए और अधिक काम नहीं करते हैं।

2

आप का उपयोग करते हैं System.Collections.Queue धागे की सुरक्षा इस तरह से गारंटी है:

var queue = new Queue(); 
Queue.Synchronized(queue).Enqueue(new WorkItem()); 
Queue.Synchronized(queue).Enqueue(new WorkItem()); 
Queue.Synchronized(queue).Clear(); 

आप चाहते उपयोग System.Collections.Generic.Queue<T> तो अपने स्वयं के आवरण वर्ग बनाते हैं। मैं System.Collections.Generic.Stack<T> के साथ इस allready किया:

using System; 
using System.Collections.Generic; 

[Serializable] 
public class SomeStack 
{ 
    private readonly object stackLock = new object(); 

    private readonly Stack<WorkItem> stack; 

    public ContextStack() 
    { 
     this.stack = new Stack<WorkItem>(); 
    } 

    public IContext Push(WorkItem context) 
    { 
     lock (this.stackLock) 
     { 
      this.stack.Push(context); 
     } 

     return context; 
    } 

    public WorkItem Pop() 
    { 
     lock (this.stackLock) 
     { 
      return this.stack.Pop(); 
     } 
    } 
} 
0

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

/// <summary> 
/// The WaitFreeQueue class implements the Queue abstract data type through a linked list. The WaitFreeQueue 
/// allows thread-safe addition and removal of elements using atomic operations. Multiple threads can add 
/// elements simultaneously, and another thread can remove elements from the queue at the same time. Only one 
/// thread can remove elements from the queue at any given time. 
/// </summary> 
/// <typeparam name="T">The type parameter</typeparam> 
public class WaitFreeQueue<T> 
{ 
    // Private fields 
    // ============== 
    #region Private fields 
    private Node<T> _tail; // The tail of the queue. 
    private Node<T> _head; // The head of the queue. 
    #endregion 



    // Public methods 
    // ============== 
    #region Public methods 
    /// <summary> 
    /// Removes the first item from the queue. This method returns a value to indicate if an item was 
    /// available, and passes the item back through an argument. 
    /// This method is not thread-safe in itself (only one thread can safely access this method at any 
    /// given time) but it is safe to call this method while other threads are enqueueing items. 
    /// 
    /// If no item was available at the time of calling this method, the returned value is initialised 
    /// to the default value that matches this instance's type parameter. For reference types, this is 
    /// a Null reference. 
    /// </summary> 
    /// <param name="value">The value.</param> 
    /// <returns>A boolean value indicating if an element was available (true) or not.</returns> 
    public bool Dequeue(ref T value) 
    { 
     bool succeeded = false; 
     value = default(T); 

     // If there is an element on the queue then we get it. 
     if (null != _head) 
     { 
      // Set the head to the next element in the list, and retrieve the old head. 
      Node<T> head = System.Threading.Interlocked.Exchange<Node<T>>(ref _head, _head.Next); 

      // Sever the element we just pulled off the queue. 
      head.Next = null; 

      // We have succeeded. 
      value = head.Value; 
      succeeded = true; 
     } 

     return succeeded; 
    } 

    /// <summary> 
    /// Adds another item to the end of the queue. This operation is thread-safe, and multiple threads 
    /// can enqueue items while a single other thread dequeues items. 
    /// </summary> 
    /// <param name="value">The value to add.</param> 
    public void Enqueue(T value) 
    { 
     // We create a new node for the specified value, and point it to itself. 
     Node<T> newNode = new Node<T>(value); 

     // In one atomic operation, set the tail of the list to the new node, and remember the old tail. 
     Node<T> previousTail = System.Threading.Interlocked.Exchange<Node<T>>(ref _tail, newNode); 

     // Link the previous tail to the new tail. 
     if (null != previousTail) 
      previousTail.Next = newNode; 

     // If this is the first node in the list, we save it as the head of the queue. 
     System.Threading.Interlocked.CompareExchange<Node<T>>(ref _head, newNode, null); 
    } // Enqueue() 
    #endregion 



    // Public constructor 
    // ================== 
    #region Public constructor 
    /// <summary> 
    /// Constructs a new WaitFreeQueue instance. 
    /// </summary> 
    public WaitFreeQueue() { } 

    /// <summary> 
    /// Constructs a new WaitFreeQueue instance based on the specified list of items. 
    /// The items will be enqueued. The list can be a Null reference. 
    /// </summary> 
    /// <param name="items">The items</param> 
    public WaitFreeQueue(IEnumerable<T> items) 
    { 
     if(null!=items) 
      foreach(T item in items) 
       this.Enqueue(item); 
    } 
    #endregion 



    // Private types 
    // ============= 
    #region Private types 
    /// <summary> 
    /// The Node class represents a single node in the linked list of a WaitFreeQueue. 
    /// It contains the queued-up value and a reference to the next node in the list. 
    /// </summary> 
    /// <typeparam name="U">The type parameter.</typeparam> 
    private class Node<U> 
    { 
     // Public fields 
     // ============= 
     #region Public fields 
     public Node<U> Next; 
     public U Value; 
     #endregion 



     // Public constructors 
     // =================== 
     #region Public constructors 
     /// <summary> 
     /// Constructs a new node with the specified value. 
     /// </summary> 
     /// <param name="value">The value</param> 
     public Node(U value) 
     { 
      this.Value = value; 
     } 
     #endregion 

    } // Node generic class 
    #endregion 

} // WaitFreeQueue class 

तो केवल एक ही धागे de-कतार होने से अधिक थ्रेड एन कतार है सकते हैं, जबकि का प्रतिबंध आपके साथ ठीक है तो आप इसका इस्तेमाल कर सकते हैं। यह खेल के लिए बहुत अच्छा था क्योंकि इसका मतलब था कि कोई धागा सिंक्रनाइज़ेशन की आवश्यकता नहीं थी।

0

उदाहरण सरल उपयोग होगा

namespace ConsoleApplication1 
{ 
    class Program 
    { 

     static void Main(string[] args) 
     { 
      ExampleQueue eq = new ExampleQueue(); 
      eq.Run(); 

      // Wait... 
      System.Threading.Thread.Sleep(100000); 
     } 


    } 

    class ExampleQueue 
    { 
     private Queue<int> _myQueue = new Queue<int>(); 

     public void Run() 
     { 
      ThreadPool.QueueUserWorkItem(new WaitCallback(PushToQueue), null); 
      ThreadPool.QueueUserWorkItem(new WaitCallback(PopFromQueue), null); 
     } 

     private void PushToQueue(object Dummy) 
     { 
      for (int i = 0; i <= 1000; i++) 
      { 
       lock (_myQueue) 
       { 
        _myQueue.Enqueue(i); 
       } 
      } 
      System.Console.WriteLine("END PushToQueue"); 

     } 

     private void PopFromQueue(object Dummy) 
     { 
      int dataElementFromQueue = -1; 
      while (dataElementFromQueue < 1000) 
      { 
       lock (_myQueue) 
       { 
        if (_myQueue.Count > 0) 
        { 
         dataElementFromQueue = _myQueue.Dequeue(); 

         // Do something with dataElementFromQueue... 
         System.Console.WriteLine("Dequeued " + dataElementFromQueue); 
        } 
       } 
      } 
      System.Console.WriteLine("END PopFromQueue"); 

     } 
    } 
} 
8

आप धागा सुरक्षा उपयोग ConcurrentQueue<T> की जरूरत है।

+0

बस ध्यान दें कि ConcurrentQueue .नेट चौखटे 4 और के लिए है चाहता हूँ; यदि आप अभी भी 3.5 या निचले ढांचे के खिलाफ विकास कर रहे हैं, तो यह आपके लिए उपलब्ध नहीं है। – Will

0

आप एक अवरुद्ध कतार का उपयोग करना चाह सकते हैं, जिसमें कतार से पॉपिंग थ्रेड कुछ डेटा उपलब्ध होने तक प्रतीक्षा करेगा।

देखें: Creating a blocking Queue<T> in .NET?

संबंधित मुद्दे