The book of inspiration

January 22, 2009

SynchronizedCounter

Filed under: c# — zproxy @ 11:13 am

This is a code post. Skip it if you do not read code.

Have you ever wondered how easy would it be to have a simple synchronized counter? This is my version of it.

The value and the date is saved in the registry. It will infer the registry path via these attributes:

    8 assembly: AssemblyTitle
   11 assembly: AssemblyCompany

This is how you would use it in an infinite loop:

  154 var c = new SynchronizedCounter.ResetEachMinute("Index0");
  155
  156     while (true)
  157     {
  158         new { Counter = c.Increment().ToString("000000") }.ToConsole();
  159
  160         Thread.Sleep(1000 + new Random().Next(2000));
  161     }

In Vista and later you will need to add permissions for the program to modify the registry at its location.

synchronizedcounter

The implementation:

   14 internal static class Extensions
   15 {
   16     public static T ToConsole<T>(this T e)
   17     {
   18         Console.WriteLine(e.ToString());
   19
   20         return e;
   21     }
   22
   23
   24     public static string PathCombine(this string[] e)
   25     {
   26         var p = e[0];
   27
   28         for (int i = 1; i < e.Length; i++)
   29         {
   30             p = Path.Combine(p, e[i]);
   31         }
   32
   33         return p;
   34     }
   35
   36     public static TReturn ReadWrite<TReturn, A, B>(this RegistryKey k, Func<A, B, TReturn> h)
   37     {
   38         return InternalReadWrite<TReturn>(k, h);
   39     }
   40
   41     public static TReturn SynchronizedReadWrite<TReturn, A, B>(this RegistryKey k, Func<A, B, TReturn> h)
   42     {
   43         var n = typeof(TReturn).GUID.ToString();
   44         var s = new Semaphore(1, 1, n);
   45         s.WaitOne();
   46         try
   47         {
   48             return InternalReadWrite<TReturn>(k.CreateSubKey(n), h);
   49         }
   50         finally
   51         {
   52             s.Release();
   53             s.Close();
   54         }
   55     }
   56
   57     static TReturn InternalReadWrite<TReturn>(this RegistryKey k, Delegate h)
   58     {
   59         var s = (TReturn)h.DynamicInvoke(
   60             Enumerable.ToArray(
   61                 from p in h.Method.GetParameters()
   62                 let kv = k.GetValue(p.Name)
   63                 let v = kv == null ?
   64                     Activator.CreateInstance(p.ParameterType) :
   65                     Convert.ChangeType(kv, p.ParameterType)
   66                 select v
   67             )
   68         );
   69
   70         foreach (var p in typeof(TReturn).GetProperties())
   71             k.SetValue(p.Name, Convert.ToString(p.GetValue(s, null)));
   72
   73         return s;
   74     }
   75 }
   76
   77 public class SynchronizedCounter
   78 {
   79     /// <summary>
   80     /// Given the last date and value you will need to provide the next value
   81     /// </summary>
   82     public Func<DateTime, int, int> IncrementImplementation;
   83
   84     public SynchronizedCounter(string Name)
   85         : this(Assembly.GetEntryAssembly(), Name)
   86     {
   87
   88     }
   89
   90     public SynchronizedCounter(Assembly SoftwareAssembly, string Name)
   91     {
   92         if (SoftwareAssembly == null)
   93         {
   94             // In design mode we cannot save to registry
   95             Increment = () => 1;
   96             return;
   97         }
   98
   99         this.IncrementImplementation = (Date, Counter) => Counter + 1;
  100
  101         var k = Registry.LocalMachine.CreateSubKey(
  102             new[]
  103             {
  104                 "Software",
  105                 ((AssemblyCompanyAttribute)SoftwareAssembly.GetCustomAttributes(typeof(AssemblyCompanyAttribute), false).Single()).Company,
  106                 ((AssemblyTitleAttribute)SoftwareAssembly.GetCustomAttributes(typeof(AssemblyTitleAttribute), false).Single()).Title,
  107                 Name
  108             }.PathCombine()
  109         );
  110
  111         Increment =
  112             () =>
  113                 k.SynchronizedReadWrite(
  114                     (DateTime Date, int Counter) =>
  115                     {
  116                         return new
  117                         {
  118                             Date = DateTime.Now,
  119                             Counter = IncrementImplementation(Date, Counter)
  120                         };
  121                     }
  122                 ).Counter;
  123     }
  124
  125     /// <summary>
  126     /// This function will read the registry, apply the increment implementation, 
  127     /// write to the registry and return the new counter
  128     /// </summary>
  129     public readonly Func<int> Increment;
  130
  131     public class ResetEachDay : SynchronizedCounter
  132     {
  133         public ResetEachDay(string Name)
  134             : base(Name)
  135         {
  136             this.IncrementImplementation =
  137                 (Date, Counter) =>
  138                     Date.Day == DateTime.Now.Day ? Counter + 1 : 1;
  139         }
  140     }
  141
  142     public class ResetEachMinute : SynchronizedCounter
  143     {
  144         public ResetEachMinute(string Name)
  145             : base(Name)
  146         {
  147             this.IncrementImplementation =
  148                 (Date, Counter) =>
  149                     Date.Minute == DateTime.Now.Minute ? Counter + 1 : 1;
  150         }
  151     }
  152 }

The Shocking Blue Green Theme. Create a free website or blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 76 other followers