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 .
Schemaläggare
Schemaläggare
Beskrivs i Design Patterns Inte

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

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) )