2009-01-12 24 views
55

Tìm một số mã mẫu (C#) để thực hiện một nhóm đơn giản.Mã cho một hồ bơi chủ đề đơn giản trong C#

Tôi đã tìm thấy một trên codeproject, nhưng codebase là rất lớn và tôi không cần tất cả các chức năng đó.

Đây là mục đích giáo dục nhiều hơn.

+4

Câu trả lời ngắn gọn là bạn không nên tự mình cuộn trừ khi đó là bài tập học tập. Nếu đó là một bài tập học tập, bạn sẽ học nhiều hơn bằng cách viết nó một mình bằng cách sao chép mã của người khác. :) –

+2

@Greg: Không có trường hợp nào bạn có thể muốn một nhóm các chủ đề độc lập với ThreadPool chuẩn hiện có? – AnthonyWJones

+1

@Anthony: Đọc những gì đã đi vào trong threadpool được xây dựng trong Joe Duffy (và những người khác) đăng tải khác nhau, tôi là hợp lý tự tin rằng bất kỳ threadpool tôi tát với nhau sẽ được bao la yếu hơn một trong đó đã tồn tại. Hồ bơi thread –

Trả lời

28

Không cần phải triển khai của riêng bạn, vì việc triển khai .NET hiện tại không khó lắm.

Từ http://msdn.microsoft.com/en-us/library/3dasc8as(VS.80).aspx:

using System; 
using System.Threading; 

public class Fibonacci 
{ 
    public Fibonacci(int n, ManualResetEvent doneEvent) 
    { 
     _n = n; 
     _doneEvent = doneEvent; 
    } 

    // Wrapper method for use with thread pool. 
    public void ThreadPoolCallback(Object threadContext) 
    { 
     int threadIndex = (int)threadContext; 
     Console.WriteLine("thread {0} started...", threadIndex); 
     _fibOfN = Calculate(_n); 
     Console.WriteLine("thread {0} result calculated...", threadIndex); 
     _doneEvent.Set(); 
    } 

    // Recursive method that calculates the Nth Fibonacci number. 
    public int Calculate(int n) 
    { 
     if (n <= 1) 
     { 
      return n; 
     } 

     return Calculate(n - 1) + Calculate(n - 2); 
    } 

    public int N { get { return _n; } } 
    private int _n; 

    public int FibOfN { get { return _fibOfN; } } 
    private int _fibOfN; 

    private ManualResetEvent _doneEvent; 
} 

public class ThreadPoolExample 
{ 
    static void Main() 
    { 
     const int FibonacciCalculations = 10; 

     // One event is used for each Fibonacci object 
     ManualResetEvent[] doneEvents = new ManualResetEvent[FibonacciCalculations]; 
     Fibonacci[] fibArray = new Fibonacci[FibonacciCalculations]; 
     Random r = new Random(); 

     // Configure and launch threads using ThreadPool: 
     Console.WriteLine("launching {0} tasks...", FibonacciCalculations); 
     for (int i = 0; i < FibonacciCalculations; i++) 
     { 
      doneEvents[i] = new ManualResetEvent(false); 
      Fibonacci f = new Fibonacci(r.Next(20,40), doneEvents[i]); 
      fibArray[i] = f; 
      ThreadPool.QueueUserWorkItem(f.ThreadPoolCallback, i); 
     } 

     // Wait for all threads in pool to calculation... 
     WaitHandle.WaitAll(doneEvents); 
     Console.WriteLine("All calculations are complete."); 

     // Display the results... 
     for (int i= 0; i<FibonacciCalculations; i++) 
     { 
      Fibonacci f = fibArray[i]; 
      Console.WriteLine("Fibonacci({0}) = {1}", f.N, f.FibOfN); 
     } 
    } 
} 
+7

có những hạn chế rất lớn – Jeff

+1

@ Jeffrey: Xây dựng. – GEOCHET

+13

một hồ bơi cho mỗi miền ứng dụng, không thể thử hủy bỏ đề xuất đang chờ xử lý, v.v. Có rất nhiều thông tin ngoài kia http://stackoverflow.com/questions/145304/ http://www.codeproject.com/KB/ chủ đề/smartthreadpool.aspx http://www.codeproject.com/KB/threads/cancellablethreadpool.aspx – Jeff

47

Đây là, ngây thơ, thực hiện thread-pool đơn giản nhất cho các mục đích giáo dục tôi có thể đưa ra (C#/NET 3.5). Nó không sử dụng việc thực hiện pool của thread của .NET theo bất kỳ cách nào.

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

namespace SimpleThreadPool 
{ 
    public sealed class Pool : IDisposable 
    { 
     public Pool(int size) 
     { 
      this._workers = new LinkedList<Thread>(); 
      for (var i = 0; i < size; ++i) 
      { 
       var worker = new Thread(this.Worker) { Name = string.Concat("Worker ", i) }; 
       worker.Start(); 
       this._workers.AddLast(worker); 
      } 
     } 

     public void Dispose() 
     { 
      var waitForThreads = false; 
      lock (this._tasks) 
      { 
       if (!this._disposed) 
       { 
        GC.SuppressFinalize(this); 

        this._disallowAdd = true; // wait for all tasks to finish processing while not allowing any more new tasks 
        while (this._tasks.Count > 0) 
        { 
         Monitor.Wait(this._tasks); 
        } 

        this._disposed = true; 
        Monitor.PulseAll(this._tasks); // wake all workers (none of them will be active at this point; disposed flag will cause then to finish so that we can join them) 
        waitForThreads = true; 
       } 
      } 
      if (waitForThreads) 
      { 
       foreach (var worker in this._workers) 
       { 
        worker.Join(); 
       } 
      } 
     } 

     public void QueueTask(Action task) 
     { 
      lock (this._tasks) 
      { 
       if (this._disallowAdd) { throw new InvalidOperationException("This Pool instance is in the process of being disposed, can't add anymore"); } 
       if (this._disposed) { throw new ObjectDisposedException("This Pool instance has already been disposed"); } 
       this._tasks.AddLast(task); 
       Monitor.PulseAll(this._tasks); // pulse because tasks count changed 
      } 
     } 

     private void Worker() 
     { 
      Action task = null; 
      while (true) // loop until threadpool is disposed 
      { 
       lock (this._tasks) // finding a task needs to be atomic 
       { 
        while (true) // wait for our turn in _workers queue and an available task 
        { 
         if (this._disposed) 
         { 
          return; 
         } 
         if (null != this._workers.First && object.ReferenceEquals(Thread.CurrentThread, this._workers.First.Value) && this._tasks.Count > 0) // we can only claim a task if its our turn (this worker thread is the first entry in _worker queue) and there is a task available 
         { 
          task = this._tasks.First.Value; 
          this._tasks.RemoveFirst(); 
          this._workers.RemoveFirst(); 
          Monitor.PulseAll(this._tasks); // pulse because current (First) worker changed (so that next available sleeping worker will pick up its task) 
          break; // we found a task to process, break out from the above 'while (true)' loop 
         } 
         Monitor.Wait(this._tasks); // go to sleep, either not our turn or no task to process 
        } 
       } 

       task(); // process the found task 
       lock(this._tasks) 
       { 
        this._workers.AddLast(Thread.CurrentThread); 
       } 
       task = null; 
      } 
     } 

     private readonly LinkedList<Thread> _workers; // queue of worker threads ready to process actions 
     private readonly LinkedList<Action> _tasks = new LinkedList<Action>(); // actions to be processed by worker threads 
     private bool _disallowAdd; // set to true when disposing queue but there are still tasks pending 
     private bool _disposed; // set to true when disposing queue and no more tasks are pending 
    } 


    public static class Program 
    { 
     static void Main() 
     { 
      using (var pool = new Pool(5)) 
      { 
       var random = new Random(); 
       Action<int> randomizer = (index => 
       { 
        Console.WriteLine("{0}: Working on index {1}", Thread.CurrentThread.Name, index); 
        Thread.Sleep(random.Next(20, 400)); 
        Console.WriteLine("{0}: Ending {1}", Thread.CurrentThread.Name, index); 
       }); 

       for (var i = 0; i < 40; ++i) 
       { 
        var i1 = i; 
        pool.QueueTask(() => randomizer(i1)); 
       } 
      } 
     } 
    } 
} 
+1

+1 Cảm ơn bạn. Tôi đã sử dụng đoạn mã này nhưng sau một khoảng thời gian rất dài, tôi gặp lỗi: 'Ngoại lệ: System.NullReferenceException: Tham chiếu đối tượng không được đặt thành một thể hiện của đối tượng. tại System.Collections.Generic.LinkedList'1.InternalInsertNodeBefore (LinkedListNode> ''node, LinkedListNode'1 newNode) tại System.Collections.Generic.LinkedList'1.AddLast (giá trị T) tại Prog.Pool.Worker()'. có biết thứ gì gây ra không? – Legend

+2

@Legend không chắc chắn vấn đề có thể là gì, nhưng nếu tôi phải đoán tôi muốn nói nó liên quan đến thực tế là danh sách liên kết '_workers' đang được truy cập bên ngoài khóa. Nếu sử dụng .NET 4, bạn có thể thử sử dụng 'ConcurrentQueue ' thay thế. –

+1

+1 Cảm ơn bạn. Bạn đúng rồi. Tôi hỏi một câu hỏi ở đây: http://stackoverflow.com/questions/16763626/nullreferenceexception-when-creating-a-thread Có vẻ như vấn đề là do khóa bị thiếu. Cảm ơn vì đã dành thời gian cho tôi. Tôi hiện đang sử dụng NET 3.5. Và điều này hoạt động như một say mê. – Legend

Các vấn đề liên quan