Clever Geek Handbook
πŸ“œ ⬆️ ⬇️

Scheduler (design pattern)

Scheduler ( eng. Scheduler ) - a parallel design template that provides a mechanism for implementing the planning policy, but at the same time independent of any particular policy. It controls the order in which the threads have to execute sequential code using an object that explicitly sets the sequence of waiting threads.

Scheduler
Scheduler
Described in Design PatternsNot

Motives

  • Several threads may require access to a resource at a time, and only one thread at a time can access the resource.
  • Consistent with the requirements of the program, threads must access the resource in a specific order.

Implementation Example

C # Example

  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 ));
                 // the call will not be executed until the Scheduler object decides
                 // that it was the turn to print this JournalEntry object
                 _scheduler .  Enter ( journalEntry );
                 Console  WriteLine ( String . Format ( @ "{0}: start printing" , id ));
                 try
                 {
                     // TODO Something
                     journalEntry .  Do ( id );
                 }
                 finally
                 {
                     // calling the Done method tells Scheduler that the JournalEntry is
                     // printed, and the print queue of another object may come up
                     // 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>
     /// Class instances in this role control the processing of objects Request <see cref = "JournalEntry" />,
     /// executed by the Processor <see cref = "Printer" /> object.  To be type independent
     /// requests, the class <see cref = "Scheduler" /> should not know anything about the Request class it manages.
     /// Instead, it accesses the Request objects via the <see cref = "ISchedulerOrdering" /> interface they implement.
     /// </summary>
     class Scheduler
     {
         /// <summary>
         /// Thread synchronization object
         /// </summary>
         private AutoResetEvent _event = new AutoResetEvent ( false );

         /// <summary>
         /// Set to null if the resource managed by the Scheduler is not busy.
         /// </summary>
         private thread _runningThread ;

         /// <summary>
         /// Threads and their requests pending execution
         /// </summary>
         private Dictionary < Thread , ISchedulerOrdering > _waiting = new Dictionary < Thread , ISchedulerOrdering > ();

         /// <summary>
         /// The <see cref = "Enter" /> method is called before the thread starts using the managed resource.
         /// The method is not executed until the managed resource is released and the <see cref = "Sheduler" /> object
         /// will not decide that the queue for executing this request has come
         /// </summary>
         /// <param name = "s"> </param>
         public void Enter ( ISchedulerOrdering s )
         {
             var thisThread = Thread .  CurrentThread ;

             lock ( this )
             {
                 // Determine if the scheduler is busy
                 if ( _runningThread == null )
                 {
                     // Immediately start executing the request
                     _runningThread = thisThread ;
                     return
                 }
                 _waiting .  Add ( thisThread , s );
             }
            
             lock ( thisThread )
             {
                 // Block the thread until the scheduler decides to make it current
                 while ( thisThread ! = _runningThread )
                 {
                     _event .  WaitOne ();
                     _event .  Set ();  // enable other threads to check their status
                     Thread  Sleep ( 1 );
                 }
                 _event .  Reset ();
             }

             lock ( this )
             {
                 _waiting .  Remove ( thisThread );
             }
         }

         /// <summary>
         /// Calling the <see cref = "Done" /> method indicates that the current thread has completed
         /// and the managed resource is freed
         /// </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>
     /// Helper class
     /// </summary>
     static partial class ConvertTo
     {
         /// <summary>
         /// Get the first item in the collection
         /// </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>
     /// If several operations are waiting for access to a resource, the <see cref = "Scheduler" /> class uses
     /// this interface for determining the order of operations.
     /// </summary>
     interface ISchedulerOrdering
     {
         Boolean ScheduleBefore ( ISchedulerOrdering s );
     }
 }


  using System ;
 using System.Threading ;

 namespace Digital_Patterns.Concurrency.Sheduler
 {
     /// <summary>
     /// Sample code for the class <see cref = "JournalEntry" />, which should be
     /// printed by class <see cref = "Printer" />
     /// </summary>
     class JournalEntry : ISchedulerOrdering
     {
         private static DateTime mTime = DateTime .  Now ;

         private DateTime _time ;

         /// <summary>
         /// Returns the creation time of this object
         /// </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>
         /// Returns true if the given request should
         /// be processed before this request.
         /// </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 ();
         }
     }
 }

Links

  • Mark Grand. Patterns in Java Volume 1: A Catalog of Reusable Design Patterns Illustrated with UML. - Wiley & Sons, 1998 .-- 480 p. - ISBN 0471258393 . (see synopsis )
Source - https://ru.wikipedia.org/w/index.php?title= Planner_ ( Project_Template)&oldid = 100076043


More articles:

  • Pitting
  • NGC 1940
  • Surmatash State Nature Reserve
  • NGC 1948
  • NGC 1955
  • Nutcrack Crusader
  • Indexing (Economy)
  • NGC 1962
  • Kilaim
  • Czechoslovakia at the Olympics

All articles

Clever Geek | 2019