Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /// <summary>Represents a callback method to be executed by an Actor.</summary>
- /// <typeparam name="TReply">The type of reply.</typeparam>
- /// <param name="reply">The reply made by the actor.</param>
- public delegate void ActorReplyCallback<TReply>(TReply reply);
- /// <summary>Represents an Actor which receives and processes messages in concurrent applications.</summary>
- /// <typeparam name="TMessage">The type of message this actor accepts.</typeparam>
- /// <typeparam name="TReply">The type of reply made by this actor.</typeparam>
- public abstract class Actor<TMessage, TReply> : IDisposable
- {
- /// <summary></summary>
- private readonly Locker Locker;
- /// <summary>Stores the messages until they can be processed.</summary>
- private readonly System.Collections.Generic.Queue<Message> MessageQueue;
- /// <summary>Serializes access to the MessageQueue.</summary>
- private readonly ManualResetEvent EnqueueEvent;
- /// <summary>Signals the actor thread to process a new message.</summary>
- private readonly ManualResetEvent PostEvent;
- /// <summary>This tells the actor thread to stop reading from the queue.</summary>
- private readonly ManualResetEvent DisposeEvent;
- /// <summary>Processes the messages posted to the actor.</summary>
- private readonly List<Thread> ActorThreads;
- /// <summary>Initializes a new instance of the Genex.Concurrency<TRequest, TResponse> class.</summary>
- public Actor() : this(1) { }
- /// <summary>Initializes a new instance of the Genex.Concurrency<TRequest, TResponse> class.</summary>
- public Actor(Int32 total_threads)
- {
- if (total_threads < 1) throw new ArgumentOutOfRangeException("total_threads", total_threads, "Must be 1 or greater.");
- Locker = new Locker();
- MessageQueue = new System.Collections.Generic.Queue<Message>();
- EnqueueEvent = new ManualResetEvent(true);
- PostEvent = new ManualResetEvent(false);
- DisposeEvent = new ManualResetEvent(true);
- ActorThreads = new List<Thread>();
- for (Int32 i = 0; i < total_threads; i++)
- {
- var thread = new Thread(ProcessMessages);
- thread.IsBackground = true;
- thread.Start();
- ActorThreads.Add(thread);
- }
- }
- /// <summary>Posts a message and waits for the reply.</summary>
- /// <param name="value">The message to post to the actor.</param>
- /// <returns>The reply from the actor.</returns>
- public TReply PostWithReply(TMessage message)
- {
- using (var wrapper = new Message(message))
- {
- lock (Locker) MessageQueue.Enqueue(wrapper);
- PostEvent.Set();
- wrapper.Channel.CompleteEvent.WaitOne();
- return wrapper.Channel.Value;
- }
- }
- /// <summary>Posts a message to the actor and executes the callback when the reply is received.</summary>
- /// <param name="value">The message to post to the actor.</param>
- /// <param name="callback">The callback that will be invoked once the replay is received.</param>
- public void PostWithAsyncReply(TMessage value, ActorReplyCallback<TReply> callback)
- {
- if (callback == null) throw new ArgumentNullException("callback");
- ThreadPool.QueueUserWorkItem(state => callback(PostWithReply(value)));
- }
- /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
- public void Dispose()
- {
- if (DisposeEvent.WaitOne(10))
- {
- DisposeEvent.Reset();
- EnqueueEvent.Reset();
- PostEvent.Set();
- foreach (var thread in ActorThreads)
- {
- thread.Join();
- }
- ((IDisposable)EnqueueEvent).Dispose();
- ((IDisposable)PostEvent).Dispose();
- ((IDisposable)DisposeEvent).Dispose();
- }
- }
- /// <summary>Processes a message posted to the actor.</summary>
- /// <param name="message">The message to be processed.</param>
- protected abstract void ProcessMessage(Message message);
- /// <summary>Dequeues the messages passes them to ProcessMessage.</summary>
- private void ProcessMessages()
- {
- while (PostEvent.WaitOne() && DisposeEvent.WaitOne(10))
- {
- var message = (Message)null;
- while (true)
- {
- lock (Locker)
- {
- message = MessageQueue.Count > 0 ?
- MessageQueue.Dequeue() :
- null;
- }
- if (message == null)
- {
- PostEvent.Reset();
- break;
- }
- try
- {
- ProcessMessage(message);
- }
- catch
- {
- }
- }
- }
- }
- /// <summary>Represents a message that is passed to an actor.</summary>
- protected class Message : IDisposable
- {
- /// <summary>The actual value of this message.</summary>
- public TMessage Value { get; private set; }
- /// <summary>The channel used to give a reply to this message.</summary>
- public Channel Channel { get; private set; }
- /// <summary>Initializes a new instance of Genex.Concurrency.Message class.</summary>
- /// <param name="value">The actual value of the message.</param>
- public Message(TMessage value)
- {
- Value = value;
- Channel = new Channel();
- }
- /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
- public void Dispose()
- {
- Channel.Dispose();
- }
- }
- /// <summary>Represents a channel used by an actor to reply to a message.</summary>
- protected class Channel : IDisposable
- {
- /// <summary>The value of the reply.</summary>
- public TReply Value { get; private set; }
- /// <summary>Signifies that the message has been replied to.</summary>
- public ManualResetEvent CompleteEvent { get; private set; }
- /// <summary>Initializes a new instance of Genex.Concurrency.Channel class.</summary>
- public Channel()
- {
- CompleteEvent = new ManualResetEvent(false);
- }
- /// <summary>Reply to the message received.</summary>
- /// <param name="value">The value of the reply.</param>
- public void Reply(TReply value)
- {
- Value = value;
- CompleteEvent.Set();
- }
- /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
- public void Dispose()
- {
- ((IDisposable)CompleteEvent).Dispose();
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment