Schemaläggare (designmönster)
Den aktuella versionen av sidan har ännu inte granskats av erfarna bidragsgivare och kan skilja sig väsentligt från
versionen som granskades den 28 maj 2019; kontroller kräver
4 redigeringar .
En schemaläggare är ett parallellt designmönster som tillhandahåller en mekanism för att implementera en schemaläggningspolicy, men som inte är beroende av någon särskild policy. Styr i vilken ordning trådar ska köra sekventiell kod, med hjälp av ett objekt som uttryckligen anger sekvensen av väntande trådar.
Motiv
- Flera trådar kan komma åt en resurs samtidigt, och endast en tråd åt gången kan komma åt en resurs.
- I enlighet med kraven i programmet måste trådar komma åt resursen i en viss ordning.
Implementeringsexempel
C# exempel
använder System ;
namnområde Digital_Patterns.Concurrency.Sheduler
{
class Printer
{
private static Int32 mID = 0 ;
privat Scheduler _scheduler = ny Scheduler ();
public void Skriv ut ( JournalEntry journalEntry )
{
Int32 id = ++ mID ;
prova
{
Console . WriteLine ( String . Format ( @"{0}: ange schemaläggare" , id ));
// anropet kommer inte att exekveras förrän Scheduler-objektet
// beslutar att det är dags att skriva ut detta JournalEntry
_scheduler-objekt . Enter ( journalEntry );
Konsol . WriteLine ( String . Format ( @"{0}: börja skriva ut" , id ));
prova
{
//TODO Something
journalEntry . Gör ( id );
}
finally
{
// anropar Done-metoden talar om för Scheduler att // JournalEntry-objektet har skrivits
ut och att ett annat
// JournalEntry
_scheduler- objekt kan finnas bredvid print . Klar ();
Konsol . WriteLine ( String . Format ( @"{0}: klar schemaläggare" , id ));
}
}
catch ( Undantag ) {}
}
}
}
använder System ;
använder System.Collections.Generic ;
använder System.Threading ;
namnutrymme Digital_Patterns.Concurrency.Sheduler
{
/// <summary>
/// Klassinstanser i denna roll styr bearbetningen av Request-objekt <see cref="JournalEntry"/>
/// som utförs av Processor-objektet <see cref="Printer "/> . För att vara oberoende av
/// begärandetyper behöver klassen <see cref="Scheduler"/> inte veta något om den Request-klass den hanterar.
/// Istället får den åtkomst till Request-objekt via gränssnittet de implementerar <see cref="ISchedulerOrdering"/>
/// </summary>
class Scheduler
{
/// <summary>
/// Trådsynkroniseringsobjekt
/// </ summary>
private AutoResetEvent _event = new AutoResetEvent ( false );
/// <sammanfattning>
/// Ställ in på null om resursen som hanteras av schemaläggaren är inaktiv.
/// </summary>
privat tråd _runningThread ;
/// <summary>
/// Trådar och deras förfrågningar väntar
/// </summary>
privat ordbok < Thread , ISchedulerOrdering > _waiting = ny ordbok < Thread , ISchedulerOrdering >();
/// <sammanfattning>
/// Metoden <see cref="Enter"/> anropas innan tråden börjar använda den hanterade resursen.
/// Metoden exekveras inte förrän den hanterade resursen frigörs och <see cref="Sheduler"/> objektet
/// beslutar att denna begärans exekveringskö har anlänt
/// </summary>
/// <param name ="s"></param>
public void Enter ( ISchedulerOrdering s )
{
var thisThread = Tråd . CurrentThread ;
lock ( this )
{
// Bestäm om schemaläggaren är upptagen
if ( _runningThread == null )
{
// Börja genast exekvera den inkommande begäran
_runningThread = thisThread ;
återvända ;
}
_väntar . Lägg till ( denna tråd , s );
}
lock ( thisThread )
{
// Blockera tråden tills schemaläggaren bestämmer sig för att göra den till den aktuella tråden
while ( thisThread != _runningThread )
{
_event . waitone ();
_händelse . set (); // låt andra trådar kontrollera deras tillstånd
Tråd . sömn ( 1 );
}
_händelse . återställ ();
}
lås ( detta )
{
_waiting . Ta bort ( denna tråden );
}
}
/// <summary>
/// Att anropa metoden <see cref="Done"/> indikerar att den aktuella tråden har avslutats
/// och den hanterade resursen har frigjorts
/// </summary>
public void Klar ()
{
lock ( this )
{
if ( _runningThread != Thread . CurrentThread )
throw new ThreadStateException ( @"Fel tråd" );
Int32 waitCount = _waiting . räkna ;
if ( waitCount <= 0 )
{
_runningThread = null ;
}
else if ( waitCount == 1 )
{
_runningThread = _waiting . först (). nyckel ;
_väntar . Ta bort ( _runningThread );
_händelse . set ();
}
annat
{
var nästa = _väntar . först ();
foreach ( var wait in _waiting )
{
if ( wait . Value . ScheduleBefore ( next . Value ))
{
next = wait ;
}
}
_runningThread = nästa . nyckel ;
_händelse . set ();
}
}
}
}
/// <summary>
/// Hjälparklass
/// </summary>
statisk partiell klass ConvertTo
{
/// <summary>
/// Hämta det första elementet i samlingen
/// </summary>
/// < param name= "collection"></param>
/// <returns></returns>
public static KeyValuePair < Thread , ISchedulerOrdering > First ( denna ordbok < Thread , ISchedulerOrdering > collection )
{
foreach ( var artikel i samlingen )
{
returnera föremål ;
}
kasta nytt ArgumentException ();
}
}
}
använder System ;
namespace Digital_Patterns.Concurrency.Sheduler
{
/// <summary>
/// Om flera operationer väntar på att få tillgång till en resurs, använder klassen <see cref="Scheduler"/>
/// detta gränssnitt för att bestämma i vilken ordning operationer bör utföras.
/// </summary>
gränssnitt ISchedulerOrdering
{
Boolean ScheduleBefore ( ISchedulerOrdering s );
}
}
använder System ;
använder System.Threading ;
namespace Digital_Patterns.Concurrency.Sheduler
{
/// <summary>
/// Exempel på <see cref="JournalEntry"/> klasskod som ska
/// skrivas ut av <see cref="Printer"/>
/// < /summary >
class JournalEntry : ISchedulerOrdering
{
private static DateTime mTime = DateTime . nu ;
privat DateTime _time ;
/// <summary>
/// Returnerar skapandet av detta objekt
/// </summary>
public DateTime Time { get { return _time ; } }
privat String_msg ; _
public JournalEntry ( String msg )
{
mTime = mTime . AddSeconds ( 1 );
_tid = mTid ;
_msg = msg ;
}
public void Gör ( Int32 id )
{
Console . WriteLine ( String . Format ( @"{0}: Börja göra : {1} : {2}" , id , _time , _msg ));
tråd . Sömn ( 1000 );
Konsol . WriteLine ( String . Format ( @"{0}: Finish do : {1} : {2}" , id , _time , _msg ));
}
/// <sammanfattning>
/// Returnerar sant om denna begäran
/// ska behandlas före denna begäran.
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public Boolean ScheduleBefore ( ISchedulerOrdering s )
{
if ( s is JournalEntry )
{
var otherJournalEntry = ( JournalEntry ) s ;
return ( denna . Time < otherJournalEntry . Time );
}
returnera falskt ;
}
}
}
använder System ;
använder System.Threading ;
namespace Digital_Patterns.Concurrency.Sheduler
{
public class Exempel01
{
privat Printer _printer ;
public void Kör ()
{
Console . WriteLine ( @"Tryck på valfri tangent för start, och tryck igen för att avsluta" );
Konsol . ReadKey ();
_printer = ny skrivare ();
ny tråd ( tråd1 ). Start ();
ny tråd ( tråd 2 ). Start ();
ny tråd ( tråd 3 ). Start ();
Konsol . ReadKey ();
}
private void Thread1 ()
{
var msg1 = new JournalEntry ( @"Köp avgift 5,45 USD" );
var msg2 = new JournalEntry ( @"Köp godis 1,05 USD" );
var msg3 = new JournalEntry ( @"Köp choklad 3,25 USD" );
_skrivare . Skriv ut ( msg1 );
_skrivare . Skriv ut ( msg2 );
_skrivare . Skriv ut ( msg3 );
}
private void Thread2 ()
{
var msg4 = new JournalEntry ( @"Köp vykort 2,05 USD" );
var msg5 = new JournalEntry ( @"Köp gerland 37,78 USD" );
_skrivare . Skriv ut ( msg4 );
_skrivare . Skriv ut ( msg5 );
}
private void Thread3 ()
{
var msg6 = new JournalEntry ( @"Köp boll 30,06 USD" );
var msg7 = new JournalEntry ( @"Köp rör 1,83 USD" );
_skrivare . Skriv ut ( msg6 );
_skrivare . Skriv ut ( msg7 );
}
}
}
använder System ;
använder Digital_Patterns.Concurrency.Sheduler ;
namnutrymme Digital_Patterns
{
class Program
{
static void Main ( sträng [] args )
{
new Example01 (). köra ();
Konsol . WriteLine ( @"Tryck på valfri tangent för att avsluta" );
Konsol . ReadKey ();
}
}
}
Länkar
- Mark grand. Mönster i Java Volym 1: En katalog över återanvändbara designmönster illustrerade med UML. - Wiley & Sons, 1998. - 480 sid. — ISBN 0471258393 . (se synopsis (engelska) )