Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Ответы к экзамену 0

.4.pdf
Скачиваний:
38
Добавлен:
28.06.2014
Размер:
13.27 Mб
Скачать

public 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();

}

}