Ответы к экзамену 0.4, страница 3
Описание файла
PDF-файл из архива "Ответы к экзамену 0.4", который расположен в категории "". Всё это находится в предмете "распределённые ис и базы данных" из 9 семестр (1 семестр магистратуры), которые можно найти в файловом архиве НИУ «МЭИ» . Не смотря на прямую связь этого архива с НИУ «МЭИ» , его также можно найти и в других разделах. Архив можно найти в разделе "к экзамену/зачёту", в предмете "распределённые ис и базы данных" в общих файлах.
Просмотр PDF-файла онлайн
Текст 3 страницы из PDF
Чтобы быть независимыми от типов/// запросов, класс <see cref="Scheduler"/> не должен ничего знать об управляемом им классе Requect./// Вместо этого он осущуствляет доступ к объектам Request через реализуемый ими интерфейс <seecref="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 SomethingjournalEntry.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);}}usingusingusingusingusingSystem;System.Collections.Generic;System.Text;System.Threading;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 ofbeing disposed, can't add anymore"); }if (this._disposed) { throw new ObjectDisposedException("This Pool instance has already beendisposed"); }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();}}( , , ,){ }.