Планировщик (шаблон проектирования)

Из Википедии, бесплатной энциклопедии

Планировщик
Scheduler
Описан в Design Patterns Нет

Планировщик (англ. scheduler) — параллельный шаблон проектирования, обеспечивающий механизм реализации политики планирования, но при этом не зависящий ни от одной конкретной политики. Управляет порядком, в соответствии с которым потокам предстоит выполнить последовательный код , используя для этого объект, который явным образом задаёт последовательность ожидающих потоков.

Мотивы[править | править код]

  • Несколько потоков могут потребовать доступ к ресурсу одновременно, и только один поток в какой-то момент времени может осуществить доступ к ресурсу.
  • Согласуясь с требованиями программы, потоки должны осуществлять доступ к ресурсу в определенном порядке.

Пример реализации[править | править код]

Пример C#[править | править код]

using System;  namespace Digital_Patterns.Concurrency.Sheduler {     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) {}         }     } } 


using System; using System.Collections.Generic; using System.Threading;  namespace Digital_Patterns.Concurrency.Sheduler {     /// <summary>     /// Экземпляры классов в этой роли управляют обработкой объектов Request <see cref="JournalEntry"/>,     /// выполняемой объектом Processor <see cref="Printer"/>. Чтобы быть независимыми от типов     /// запросов, класс <see cref="Scheduler"/> не должен ничего знать об управляемом им классе Request.     /// Вместо этого он осуществляет доступ к объектам 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();         }     }  } 


using System;  namespace Digital_Patterns.Concurrency.Sheduler {     /// <summary>     /// Если несколько операций ожидают доступа к ресурсу, класс<see cref="Scheduler"/> использует     /// данный интерфейс для определения порядка выполнения операций.     /// </summary>     interface ISchedulerOrdering     {         Boolean ScheduleBefore(ISchedulerOrdering s);     } } 


using System; using System.Threading;  namespace Digital_Patterns.Concurrency.Sheduler {     /// <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;         }     } } 


using System; using System.Threading;  namespace Digital_Patterns.Concurrency.Sheduler {     public class Example01     {         private Printer _printer;          public void Run()         {             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();         }          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);         }          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);         }          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 Digital_Patterns.Concurrency.Sheduler;  namespace Digital_Patterns {     class Program     {         static void Main(string[] args)         {             new Example01().Run();              Console.WriteLine(@"Press any key for end");             Console.ReadKey();         }     } } 

Ссылки[править | править код]

  • Mark Grand. Patterns in Java Volume 1: A Catalog of Reusable Design Patterns Illustrated with UML. — Wiley & Sons, 1998. — 480 с. — ISBN 0471258393. (см. синопсис  (англ.))