Plánovač (návrhový vzor)
Aktuální verze stránky ještě nebyla zkontrolována zkušenými přispěvateli a může se výrazně lišit od
verze recenzované 28. května 2019; kontroly vyžadují
4 úpravy .
Plánovač je paralelní návrhový vzor , který poskytuje mechanismus pro implementaci plánovací politiky, ale nezávisí na žádné konkrétní politice. Řídí pořadí, ve kterém by vlákna měla spustit sekvenční kód, pomocí objektu, který explicitně určuje sekvenci čekajících vláken.
Motivy
- Ke zdroji může přistupovat více vláken současně a ke zdroji může přistupovat vždy pouze jedno vlákno.
- V souladu s požadavky programu musí vlákna přistupovat ke zdroji v určitém pořadí.
Příklad implementace
C# příklad
pomocí System ;
jmenný prostor Digital_Patterns.Concurrency.Sheduler
{
class Printer
{
private static Int32 mID = 0 ;
private Scheduler _scheduler = new Scheduler ();
public void Tisk ( JournalEntry journalEntry )
{
Int32 id = ++ mID ;
zkuste
{
Console . WriteLine ( String . Format ( @"{0}: zadejte plánovač" , id ));
// volání nebude provedeno, dokud objekt Scheduler
// nerozhodne, že je čas vytisknout tento
objekt JournalEntry _scheduler . Enter ( journalEntry );
Konzole . WriteLine ( String . Format ( @"{0}: zahájení tisku" , id ));
try
{
//TODO Something
journalEntry . Do ( id );
}
konečně
{
// volání metody Done sdělí plánovači, že objekt // JournalEntry byl
vytištěn a další objekt
// JournalEntry
_scheduler může být vedle print . Hotovo ();
Konzole . WriteLine ( String . Format ( @"{0}: hotový plánovač" , id ));
}
}
catch ( výjimka ) {}
}
}
}
pomocí System ;
pomocí System.Collections.Generic ;
pomocí System.Threading ;
jmenný prostor Digital_Patterns.Concurrency.Sheduler
{
/// <summary>
/// Instance tříd v této roli řídí zpracování objektů požadavku <viz cref="JournalEntry"/>
/// prováděné objektem Processor <viz cref="Tiskárna "/>. Aby byla třída <viz cref="Scheduler"/> nezávislá na
/// typech požadavků, nemusí vědět nic o třídě Request, kterou spravuje.
/// Místo toho přistupuje k objektům Request prostřednictvím rozhraní, které implementují <viz cref="ISchedulerOrdering"/>
/// </summary>
class Scheduler
{
/// <summary>
/// Objekt synchronizace vláken
/// < / souhrn>
private AutoResetEvent _event = new AutoResetEvent ( false );
/// <summary>
/// Nastavte na hodnotu null, pokud je zdroj spravovaný plánovačem nečinný.
/// </summary>
private Thread _runningThread ;
/// <summary>
/// Vlákna a jejich požadavky čekající
/// </summary>
private Dictionary < Thread , ISchedulerOrdering > _waiting = new Dictionary < Thread , ISchedulerOrdering >();
/// <summary>
/// Metoda <see cref="Enter"/> je volána předtím, než vlákno začne používat spravovaný prostředek.
/// Metoda není spuštěna, dokud není spravovaný prostředek uvolněn a objekt <viz cref="Sheduler"/>
/// nerozhodne, že fronta provádění tohoto požadavku dorazila
/// </summary>
/// <název parametru ="s"></param>
public void Enter ( ISchedulerOrdering s )
{
var thisThread = Thread . CurrentThread ;
lock ( this )
{
// Zjistěte , zda je plánovač zaneprázdněn
if ( _runningThread == null )
{
// Okamžitě začněte provádět příchozí požadavek
_runningThread = thisThread ;
vrátit se ;
}
_čekání . Add ( thisThread , s );
}
lock ( thisThread )
{
// Blokujte vlákno , dokud se plánovač nerozhodne udělat z něj aktuální vlákno
while ( thisThread != _runningThread )
{
_event . čekatone ();
_událost . set (); // nechat ostatní vlákna zkontrolovat jejich stav
Thread . spánek ( 1 );
}
_událost . reset ();
}
lock ( this )
{
_waiting . Odebrat ( toto vlákno );
}
}
/// <summary>
/// Volání metody <see cref="Done"/> znamená, že aktuální vlákno bylo ukončeno
/// a spravovaný zdroj byl uvolněn
/// </summary>
public void Hotovo ()
{
lock ( this )
{
if ( _runningThread != Thread . CurrentThread )
throw new ThreadStateException ( @"Wrong Thread" );
Int32 waitCount = _waiting . počítat ;
if ( waitCount <= 0 )
{
_runningThread = null ;
}
else if ( waitCount == 1 )
{
_runningThread = _waiting . první (). klíč ;
_čekání . Odebrat ( _runningThread );
_událost . set ();
}
else
{
var next = _waiting . první ();
foreach ( var wait in _waiting )
{
if ( wait . Value . ScheduleBefore ( next . Value ))
{
next = wait ;
}
}
_runningThread = další . klíč ;
_událost . set ();
}
}
}
}
/// <summary>
/// Pomocná třída
/// </summary>
statická částečná třída ConvertTo
{
/// <summary>
/// Získání prvního prvku kolekce
/// </summary>
/// < param name= "collection"></param>
/// <returns></returns>
public static KeyValuePair < Thread , ISchedulerOrdering > First ( this Dictionary < Thread , ISchedulerOrdering > collection )
{
foreach ( var item in collection )
{
vrátit položku ;
}
throw new ArgumentException ();
}
}
}
pomocí System ;
jmenný prostor Digital_Patterns.Concurrency.Sheduler
{
/// <summary>
/// Pokud na přístup ke zdroji čeká více operací, třída <see cref="Scheduler"/>
/// použije toto rozhraní k určení pořadí, ve kterém operace by měly být provedeny.
/// </summary>
interface ISchedulerOrdering
{
Boolean ScheduleBefore ( ISchedulerOrdering s );
}
}
pomocí System ;
pomocí System.Threading ;
jmenný prostor Digital_Patterns.Concurrency.Sheduler
{
/// <summary>
/// Ukázka <viz cref="JournalEntry"/> kód třídy, který má být
/// vytištěn <viz cref="Printer"/>
/// < /summary >
class JournalEntry : ISchedulerOrdering
{
private static DateTime mTime = DateTime . nyní ;
private DateTime _time ;
/// <summary>
/// Vrátí čas vytvoření tohoto objektu
/// </summary>
public DateTime Time { get { return _time ; } }
private String_msg ; _
public JournalEntry ( String msg )
{
mTime = mTime . AddSeconds ( 1 );
_time = mTime ;
_msg = zpráva ;
}
public void Do ( Int32 id )
{
Console . WriteLine ( String . Format ( @"{0}: Začít dělat : {1} : {2}" , id , _time , _msg ));
vlákno . Spánek ( 1000 );
Konzole . WriteLine ( String . Format ( @"{0}: Dokončení do: {1}: {2}" , id , _time , _msg ));
}
/// <summary>
/// Vrátí true, pokud by tento požadavek
/// měl být zpracován před tímto požadavkem.
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public Boolean ScheduleBefore ( ISchedulerOrdering s )
{
if ( s je JournalEntry )
{
var otherJournalEntry = ( JournalEntry ) s ;
return ( this . Time < otherJournalEntry . Time );
}
return false ;
}
}
}
pomocí System ;
pomocí System.Threading ;
jmenný prostor Digital_Patterns.Concurrency.Sheduler
{
public class Příklad01
{
private Printer _printer ;
public void Spustit ()
{
Console . WriteLine ( @"Stiskněte libovolnou klávesu pro začátek a znovu stiskněte pro dokončení" );
Konzole . ReadKey ();
_printer = new Printer ();
nové vlákno ( Thread1 ). Start ();
nové vlákno ( Thread2 ). Start ();
nové vlákno ( Thread3 ). Start ();
Konzole . ReadKey ();
}
private void Thread1 ()
{
var msg1 = new JournalEntry ( @"Buy toll 5,45 USD" );
var msg2 = new JournalEntry ( @"Koupit cukroví 1,05 USD" );
var msg3 = new JournalEntry ( @"Koupit čokoládu 3,25 USD" );
_tiskárna . Tisk ( msg1 );
_tiskárna . Tisk ( msg2 );
_tiskárna . Tisk ( msg3 );
}
private void Thread2 ()
{
var msg4 = new JournalEntry ( @"Koupit pohlednici 2,05 USD" );
var msg5 = new JournalEntry ( @"Koupit Německo 37,78 USD" );
_tiskárna . Tisk ( msg4 );
_tiskárna . Tisk ( msg5 );
}
private void Thread3 ()
{
var msg6 = new JournalEntry ( @"Buy ball 30.06 USD" );
var msg7 = new JournalEntry ( @"Koupit potrubí 1,83 USD" );
_tiskárna . Tisk ( msg6 );
_tiskárna . Tisk ( msg7 );
}
}
}
pomocí System ;
pomocí Digital_Patterns.Concurrency.Sheduler ;
jmenný prostor Digital_Patterns
{
class Program
{
static void Main ( string [] args )
{
new Example01 (). běh ();
Konzole . WriteLine ( @"Stiskněte libovolnou klávesu pro ukončení" );
Konzole . ReadKey ();
}
}
}
Odkazy
- Mark Grand. Vzory v Javě Volume 1: Katalog opakovaně použitelných návrhových vzorů ilustrovaných pomocí UML. - Wiley & Sons, 1998. - 480 s. — ISBN 0471258393 . (viz synopse (anglicky) )