Планировщик (шаблон проектирования)
Планировщик (англ. 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();
}
}
}
Ссылки
|
Index:
pl ar de en es fr it arz nl ja pt ceb sv uk vi war zh ru af ast az bg zh-min-nan bn be ca cs cy da et el eo eu fa gl ko hi hr id he ka la lv lt hu mk ms min no nn ce uz kk ro simple sk sl sr sh fi ta tt th tg azb tr ur zh-yue hy my ace als am an hyw ban bjn map-bms ba be-tarask bcl bpy bar bs br cv nv eml hif fo fy ga gd gu hak ha hsb io ig ilo ia ie os is jv kn ht ku ckb ky mrj lb lij li lmo mai mg ml zh-classical mr xmf mzn cdo mn nap new ne frr oc mhr or as pa pnb ps pms nds crh qu sa sah sco sq scn si sd szl su sw tl shn te bug vec vo wa wuu yi yo diq bat-smg zu lad kbd ang smn ab roa-rup frp arc gn av ay bh bi bo bxr cbk-zam co za dag ary se pdc dv dsb myv ext fur gv gag inh ki glk gan guw xal haw rw kbp pam csb kw km kv koi kg gom ks gcr lo lbe ltg lez nia ln jbo lg mt mi tw mwl mdf mnw nqo fj nah na nds-nl nrm nov om pi pag pap pfl pcd krc kaa ksh rm rue sm sat sc trv stq nso sn cu so srn kab roa-tara tet tpi to chr tum tk tyv udm ug vep fiu-vro vls wo xh zea ty ak bm ch ny ee ff got iu ik kl mad cr pih ami pwn pnt dz rmy rn sg st tn ss ti din chy ts kcg ve
Portal di Ensiklopedia Dunia