Ответы к экзамену 0
.4.pdfpublic class SynchronousEventDemultiplexer : ISynchronousEventDemultiplexer
{
public IList<TcpListener> Select(ICollection<TcpListener> listeners)
{
var tcpListeners =
new List<TcpListener>(from listener in listeners where listener.Pending() select listener);
return tcpListeners;
}
}
public interface IEventHandler
{
void HandleEvent(byte[] data); TcpListener GetHandler();
}
public class MessageEventHandler : IEventHandler
{
private readonly TcpListener _listener;
public MessageEventHandler(IPAddress ipAddress, int port)
{
_listener = new TcpListener(ipAddress, port);
}
public void HandleEvent(byte[] data)
{
string message = Encoding.UTF8.GetString(data);
}
public TcpListener GetHandler()
{
return _listener;
}
}
public interface IReactor
{
void RegisterHandle(IEventHandler eventHandler); void RemoveHandle(IEventHandler eventHandler); void HandleEvents();
}
public class Reactor : IReactor
{
ISynchronousEventDemultiplexer _synchronousEventDemultiplexer; IDictionary<TcpListener, IEventHandler> _handlers;
public Reactor(ISynchronousEventDemultiplexer synchronousEventDemultiplexer)
{
_synchronousEventDemultiplexer = synchronousEventDemultiplexer; _handlers = new Dictionary<TcpListener, IEventHandler>();
}
public void RegisterHandle(IEventHandler eventHandler)
{
_handlers.Add(eventHandler.GetHandler(), eventHandler);
}
public void RemoveHandle(IEventHandler eventHandler)
{
_handlers.Remove(eventHandler.GetHandler());
}
public void HandleEvents()
{
while (true)
{
IList<TcpListener> listeners = _synchronousEventDemultiplexer.Select(_handlers.Keys);
foreach (TcpListener listener in listeners)
{
int dataReceived = 0; byte[] buffer = new byte[1];
IList<byte> data = new List<byte>();
Socket socket = listener.AcceptSocket();
do
{
dataReceived = socket.Receive(buffer);
if (dataReceived > 0)
{
data.Add(buffer[0]);
}
} while (dataReceived > 0);
socket.Close();
_handlers[listener].HandleEvent(data.ToArray());
}
}
}
}
class Program
{
static void Main(string[] args)
{
IEventHandler client1 = new MessageEventHandler(IPAddress.Parse("123.123.123.123"), 123); IEventHandler client2 = new MessageEventHandler(IPAddress.Parse("234.234.234.234"), 123); IEventHandler client3 = new MessageEventHandler(IPAddress.Parse("125.125.125.125"), 123);
ISynchronousEventDemultiplexer synchronousEventDemultiplexer = new SynchronousEventDemultiplexer();
Reactor dispatcher = new Reactor(synchronousEventDemultiplexer);
dispatcher.RegisterHandle(client1);
dispatcher.RegisterHandle(client2);
dispatcher.RegisterHandle(client3);
dispatcher.HandleEvents();
Console.ReadKey();
}
}
Шаблон реализуется следующим образом:
using System;
using System.Collections.Generic; using System.Text;
using System.Threading;
///<summary>
///Экземпляры классов в этой роли управляют обработкой объектов Request <see cref="JournalEntry"/>,
///выполняемой объектом Processor <see cref="Printer"/>. Чтобы быть независимыми от типов
///запросов, класс <see cref="Scheduler"/> не должен ничего знать об управляемом им классе Requect.
///Вместо этого он осущуствляет доступ к объектам Request через реализуемый ими интерфейс <see cref="ISchedulerOrdering"/>
///</summary>
class Scheduler
{
///<summary>
///Объект синхронизации потоков
///</summary>
private AutoResetEvent _event = new AutoResetEvent(false);
///<summary>
///Устанавливается в null, если управляемый объектом Scheduler ресурс не занят.
///</summary>
private Thread _runningThread;
///<summary>
///Потоки и их запросы ожидающие выполнения
///</summary>
private Dictionary<Thread, ISchedulerOrdering> _waiting = new Dictionary<Thread, ISchedulerOrdering>();
///<summary>
///Метод <see cref="Enter"/> вызывается перед тем, как поток начнет использовать уравляемый ресурс.
///Метод не выполняется до тех пор пока управляемый ресур не освободиться и объект <see cref="Sheduler"/>
///не примет решение, что подошла очередь выполнения этого запроса
///</summary>
///<param name="s"></param>
public void Enter(ISchedulerOrdering s)
{
var thisThread = Thread.CurrentThread;
lock (this)
{
// Определяем не занят ли планировщик if (_runningThread == null)
{
// Немедленно начинаем выполнение поступившего запроса
_runningThread = thisThread;
return;
}
_waiting.Add(thisThread, s);
}
lock (thisThread)
{
//Блокируем поток до тех пор, пока планировщик не решит сделать его текущим while (thisThread != _runningThread)
{
_event.WaitOne();
_event.Set(); // даем возможность другим потокам проверить своё состояние
Thread.Sleep(1);
}
_event.Reset();
}
lock (this)
{
_waiting.Remove(thisThread);
}
}
///<summary>
///Вызов метода <see cref="Done"/> указывает на то, что текущий поток завершил работу
///и управляемый ресурс освободился
///</summary>
public void Done()
{
lock (this)
{
if (_runningThread != Thread.CurrentThread)
throw new ThreadStateException(@"Wrong Thread");
Int32 waitCount = _waiting.Count; if (waitCount <= 0)
{
_runningThread = null;
}
else if (waitCount == 1)
{
_runningThread = _waiting.First().Key; _waiting.Remove(_runningThread); _event.Set();
}
else
{
var next = _waiting.First(); foreach (var wait in _waiting)
{
if (wait.Value.ScheduleBefore(next.Value))
{
next = wait;
}
}
_runningThread = next.Key; _event.Set();
}
}
}
}
///<summary>
///Вспомогательный класс
///</summary>
static partial class ConvertTo
{
///<summary>
///Получить первый элемент коллекции
///</summary>
///<param name="collection"></param>
///<returns></returns>
public static KeyValuePair<Thread, ISchedulerOrdering> First (this Dictionary<Thread, ISchedulerOrdering> collection)
{
foreach (var item in collection)
{
return item;
}
throw new ArgumentException();
}
}
///<summary>
///Если несколько операций ожидают доступа к ресурсу, класс<see cref="Scheduler"/> использует
///данный интерфейс для определения порядка выполнения операций.
///</summary>
interface ISchedulerOrdering
{
Boolean ScheduleBefore(ISchedulerOrdering s);
}
///<summary>
///Примерный код класса <see cref="JournalEntry"/>, который должен быть
///распечатан классом <see cref="Printer"/>
///</summary>
class JournalEntry : ISchedulerOrdering
{
private static DateTime mTime = DateTime.Now;
private DateTime _time;
///<summary>
///Возвращает время создания этого объекта
///</summary>
public DateTime Time { get { return _time; } }
private String _msg;
public JournalEntry(String msg)
{
mTime = mTime.AddSeconds(1); _time = mTime;
_msg = msg;
}
public void Do(Int32 id)
{
Console.WriteLine(String.Format(@"{0}: Start doing : {1} : {2}", id, _time, _msg)); Thread.Sleep(1000);
Console.WriteLine(String.Format(@"{0}: Finish do : {1} : {2}", id, _time, _msg));
}
///<summary>
///Возвращает true, если данный запрос должен
///обрабатываться перед этим запросом.
///</summary>
///<param name="s"></param>
///<returns></returns>
public Boolean ScheduleBefore(ISchedulerOrdering s)
{
if (s is JournalEntry)
{
var otherJournalEntry = (JournalEntry)s; return (this.Time < otherJournalEntry.Time);
}
return false;
}
}
class Printer
{
private static Int32 mID = 0;
private Scheduler _scheduler = new Scheduler();
public void Print(JournalEntry journalEntry)
{
Int32 id = ++mID; try
{
Console.WriteLine(String.Format(@"{0}: enter scheduler", id));
//вызов не выполнится до тех пор, пока объект Scheduler не решит,
//что подошла очередь распечатать этот объект JournalEntry
_scheduler.Enter(journalEntry); Console.WriteLine(String.Format(@"{0}: start printing", id)); try
{
//TODO Something journalEntry.Do(id);
}
finally
{
//вызов метода Done говорит Scheduler о том, что объект JournalEntry
//распечатан, и может подойти очередь вывода на печать другого объекта
//JournalEntry
_scheduler.Done();
Console.WriteLine(String.Format(@"{0}: done scheduler", id));
}
}
catch (Exception) { }
}
}
class Program
{
static private Printer _printer;
static void Main(string[] args)
{
Console.WriteLine(@"Press any key for start, and press again for finish"); Console.ReadKey();
_printer = new Printer(); new Thread(Thread1).Start(); new Thread(Thread2).Start(); new Thread(Thread3).Start();
Console.ReadKey();
}
static private void Thread1()
{
var msg1 = new JournalEntry(@"Buy toll 5.45 USD"); var msg2 = new JournalEntry(@"Buy candy 1.05 USD");
var msg3 = new JournalEntry(@"Buy chocolate 3.25 USD"); _printer.Print(msg1);
_printer.Print(msg2); _printer.Print(msg3);
}
static private void Thread2()
{
var msg4 = new JournalEntry(@"Buy postcard 2.05 USD"); var msg5 = new JournalEntry(@"Buy gerland 37.78 USD"); _printer.Print(msg4);
_printer.Print(msg5);
}
static private void Thread3()
{
var msg6 = new JournalEntry(@"Buy ball 30.06 USD"); var msg7 = new JournalEntry(@"Buy pipe 1.83 USD"); _printer.Print(msg6);
_printer.Print(msg7);
}
}
using System;
using System.Collections.Generic; using System.Text;
using System.Threading; using System.Linq;
public sealed class Pool : IDisposable
{
LinkedList<Thread> _workers;
LinkedList<Action> _tasks = new LinkedList<Action>(); bool _disallowAdd;
bool _disposed;
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; while (this._tasks.Count > 0)
{
Monitor.Wait(this._tasks);
}
this._disposed = true; Monitor.PulseAll(this._tasks); 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);
}
}
private void Worker()
{
Action task = null; while (true)
{
lock (this._tasks)
{
while (true)
{
if (this._disposed)
{
return;
}
if (null != this._workers.First && object.ReferenceEquals(Thread.CurrentThread, this._workers.First.Value) && this._tasks.Count > 0)
{
task = this._tasks.First.Value; this._tasks.RemoveFirst(); this._workers.RemoveFirst(); Monitor.PulseAll(this._tasks); break;
}
Monitor.Wait(this._tasks);
}
}
task(); this._workers.AddLast(Thread.CurrentThread); task = null;
}
}
}
class Program
{
static void Main(string[] args)
{
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));
}
}
Console.ReadKey();
}
}