Guest User

ChaosPandion

a guest
Feb 23rd, 2010
363
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 6.01 KB | None | 0 0
  1. /// <summary>Represents a callback method to be executed by an Actor.</summary>
  2. /// <typeparam name="TReply">The type of reply.</typeparam>
  3. /// <param name="reply">The reply made by the actor.</param>
  4. public delegate void ActorReplyCallback<TReply>(TReply reply);
  5.  
  6. /// <summary>Represents an Actor which receives and processes messages in concurrent applications.</summary>
  7. /// <typeparam name="TMessage">The type of message this actor accepts.</typeparam>
  8. /// <typeparam name="TReply">The type of reply made by this actor.</typeparam>
  9. public abstract class Actor<TMessage, TReply> : IDisposable
  10. {
  11.     /// <summary></summary>
  12.     private readonly Locker Locker;
  13.  
  14.     /// <summary>Stores the messages until they can be processed.</summary>
  15.     private readonly System.Collections.Generic.Queue<Message> MessageQueue;
  16.  
  17.     /// <summary>Serializes access to the MessageQueue.</summary>
  18.     private readonly ManualResetEvent EnqueueEvent;
  19.  
  20.     /// <summary>Signals the actor thread to process a new message.</summary>
  21.     private readonly ManualResetEvent PostEvent;
  22.  
  23.     /// <summary>This tells the actor thread to stop reading from the queue.</summary>
  24.     private readonly ManualResetEvent DisposeEvent;
  25.  
  26.     /// <summary>Processes the messages posted to the actor.</summary>
  27.     private readonly List<Thread> ActorThreads;
  28.  
  29.    
  30.     /// <summary>Initializes a new instance of the Genex.Concurrency&lt;TRequest, TResponse&gt; class.</summary>
  31.     public Actor() : this(1) { }
  32.  
  33.     /// <summary>Initializes a new instance of the Genex.Concurrency&lt;TRequest, TResponse&gt; class.</summary>
  34.     public Actor(Int32 total_threads)
  35.     {
  36.         if (total_threads < 1) throw new ArgumentOutOfRangeException("total_threads", total_threads, "Must be 1 or greater.");
  37.  
  38.         Locker = new Locker();
  39.         MessageQueue = new System.Collections.Generic.Queue<Message>();
  40.         EnqueueEvent = new ManualResetEvent(true);
  41.         PostEvent = new ManualResetEvent(false);
  42.         DisposeEvent = new ManualResetEvent(true);
  43.         ActorThreads = new List<Thread>();
  44.  
  45.         for (Int32 i = 0; i < total_threads; i++)
  46.         {
  47.             var thread = new Thread(ProcessMessages);
  48.             thread.IsBackground = true;
  49.             thread.Start();
  50.             ActorThreads.Add(thread);
  51.         }              
  52.     }
  53.  
  54.  
  55.     /// <summary>Posts a message and waits for the reply.</summary>
  56.     /// <param name="value">The message to post to the actor.</param>
  57.     /// <returns>The reply from the actor.</returns>
  58.     public TReply PostWithReply(TMessage message)
  59.     {
  60.         using (var wrapper = new Message(message))
  61.         {
  62.             lock (Locker) MessageQueue.Enqueue(wrapper);
  63.             PostEvent.Set();
  64.             wrapper.Channel.CompleteEvent.WaitOne();
  65.             return wrapper.Channel.Value;
  66.         }
  67.     }
  68.  
  69.     /// <summary>Posts a message to the actor and executes the callback when the reply is received.</summary>
  70.     /// <param name="value">The message to post to the actor.</param>
  71.     /// <param name="callback">The callback that will be invoked once the replay is received.</param>
  72.     public void PostWithAsyncReply(TMessage value, ActorReplyCallback<TReply> callback)
  73.     {
  74.         if (callback == null) throw new ArgumentNullException("callback");
  75.         ThreadPool.QueueUserWorkItem(state => callback(PostWithReply(value)));
  76.     }
  77.  
  78.     /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
  79.     public void Dispose()
  80.     {
  81.         if (DisposeEvent.WaitOne(10))
  82.         {
  83.             DisposeEvent.Reset();
  84.             EnqueueEvent.Reset();
  85.             PostEvent.Set();
  86.  
  87.             foreach (var thread in ActorThreads)
  88.             {
  89.                 thread.Join();
  90.             }
  91.  
  92.             ((IDisposable)EnqueueEvent).Dispose();
  93.             ((IDisposable)PostEvent).Dispose();
  94.             ((IDisposable)DisposeEvent).Dispose();
  95.         }
  96.     }
  97.  
  98.     /// <summary>Processes a message posted to the actor.</summary>
  99.     /// <param name="message">The message to be processed.</param>
  100.     protected abstract void ProcessMessage(Message message);
  101.  
  102.     /// <summary>Dequeues the messages passes them to ProcessMessage.</summary>
  103.     private void ProcessMessages()
  104.     {
  105.         while (PostEvent.WaitOne() && DisposeEvent.WaitOne(10))
  106.         {
  107.             var message = (Message)null;
  108.             while (true)
  109.             {
  110.                 lock (Locker)
  111.                 {
  112.                     message = MessageQueue.Count > 0 ?
  113.                         MessageQueue.Dequeue() :
  114.                         null;
  115.                 }
  116.  
  117.                 if (message == null)
  118.                 {
  119.                     PostEvent.Reset();
  120.                     break;
  121.                 }
  122.  
  123.                 try
  124.                 {
  125.                     ProcessMessage(message);
  126.                 }
  127.                 catch
  128.                 {
  129.  
  130.                 }
  131.             }
  132.         }
  133.     }          
  134.  
  135.     /// <summary>Represents a message that is passed to an actor.</summary>
  136.     protected class Message : IDisposable
  137.     {
  138.         /// <summary>The actual value of this message.</summary>
  139.         public TMessage Value { get; private set; }
  140.  
  141.         /// <summary>The channel used to give a reply to this message.</summary>
  142.         public Channel Channel { get; private set; }
  143.  
  144.  
  145.         /// <summary>Initializes a new instance of Genex.Concurrency.Message class.</summary>
  146.         /// <param name="value">The actual value of the message.</param>
  147.         public Message(TMessage value)
  148.         {
  149.             Value = value;
  150.             Channel = new Channel();
  151.         }
  152.  
  153.  
  154.         /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
  155.         public void Dispose()
  156.         {
  157.             Channel.Dispose();
  158.         }
  159.     }
  160.  
  161.     /// <summary>Represents a channel used by an actor to reply to a message.</summary>        
  162.     protected class Channel : IDisposable
  163.     {
  164.         /// <summary>The value of the reply.</summary>
  165.         public TReply Value { get; private set; }
  166.  
  167.         /// <summary>Signifies that the message has been replied to.</summary>
  168.         public ManualResetEvent CompleteEvent { get; private set; }
  169.  
  170.  
  171.         /// <summary>Initializes a new instance of Genex.Concurrency.Channel class.</summary>
  172.         public Channel()
  173.         {
  174.             CompleteEvent = new ManualResetEvent(false);
  175.         }
  176.  
  177.         /// <summary>Reply to the message received.</summary>
  178.         /// <param name="value">The value of the reply.</param>
  179.         public void Reply(TReply value)
  180.         {
  181.             Value = value;
  182.             CompleteEvent.Set();
  183.         }
  184.  
  185.         /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
  186.         public void Dispose()
  187.         {
  188.             ((IDisposable)CompleteEvent).Dispose();
  189.         }
  190.     }
  191. }
Advertisement
Add Comment
Please, Sign In to add comment