Click here to Skip to main content
15,880,972 members
Articles / Programming Languages / C#

CCRing

Rate me:
Please Sign up or sign in to vote.
4.00/5 (5 votes)
29 Oct 2008CPOL4 min read 23.7K   115   25   2
Sequential Asynchronous logging example using the CCR

Preface

Talk about synchronicity, the day I post this article the CCR and DSS become a downloadable product. You can find the new product here. I suggest you watch this product, I suspect this to be a corner stone in concurrent .NET software development.

Introduction

I often revisit applications I've written to improve areas of the code with ideas and lessons I pick up over time. There seems to always be one primary goal and this is to improve performance. When it comes to improving performance there are many things you can do, but in the end you'll always look to multithreading. It's theoretically the simplest suggested concept but not always the easiest to implement. If you've ever run into resource sharing problems you'll know what I mean and although there are many articles on how to do it, it doesn't always mesh with every solution.

Sometime ago I came across something called the CCR, it was like magic code created by two wizards, Jeff Richter and George Chrysanthakopoulos. Part of the magic was to properly roll the syllables in Chrysanthakopoulos neatly off your tongue in one breath and when you get past that you'll see the light at the end of the multithreaded hallway of horrors. This managed DLL is packed with oodles of multithreaded fun and provides many levels of simplicity to common threading complexities. In other words, if you want to improve performance of your applications by implementing a multithreaded layer then you need to live and breathe the CCR. For some great background and fun, grab some popcorn and visit Jeff and George at this link.

Background

After watching the video cast, you should come away with some confidence and revelation along with some courage to start using the CCR. So you'll open up your latest project and... where do you start? Well one place you can start is by creating a simple asynchronous logger. Most applications I design have varying levels of logging for production diagnosis, but if you don't use a threaded model when utilizing your logger class then you've created blocking code and obvious room for improvement. So to get you started, I'll show you how to implement a CCR'd logger class that writes to a local file. There are many ways to log data but for this demo I'm using simple local logging. You will most likely be interested in this article; it will explain the many faces of the CCR.

Using the Code

The following code can be dropped into your application and be utilized right away and although basic, it can act as a replacement for any logging methods you currently implement.

The first thing we need to do is to new up something called a Dispatcher, think of this as the thread "pool". Notice the "1", this means we only want one thread handling these calls therefore all "posts" to the class will execute async but sequential. If you're writing to a SQL database you can try increasing this number but be aware that data may not arrive sequentially! When utilizing a dispatcher for other non sequential tasks, try increasing this number.

C#
//Create Dispatcher
private static readonly Dispatcher _logDispatcher = new Dispatcher(1, "LogPool");

Secondly you'll want a DispatcherQueue. The DQ manages your list of delegates to methods, methods you need to execute when needed.

C#
//Create Dispatch Queue
private static DispatcherQueue _logDispatcherQueue;

Next you need a PORT, ports are like input queues. You'll "post" to ports to invoke your registered methods.

C#
//Message Port
private static readonly Port<string> _logPort = new Port<string>();

Now for the class, don't forget to include the CCR in the directives!

C#
using System;
using System.IO;
using System.Threading;
using Microsoft.Ccr.Core;

namespace CCRing_Demo
{
    public static class DataLogger
    {
        //Create Dispatcher
        private static readonly Dispatcher _logDispatcher = new Dispatcher(1,
            ThreadPriority.Normal, false, "LogPool");

        //Create Dispatch Queue
        private static DispatcherQueue _logDispatcherQueue;

        //Message Port
        private static readonly Port<string> _logPort = new Port<string>();

        //Fields
        private static string _logFileName;

        private static void Init()
        {
            _logDispatcherQueue = new DispatcherQueue("LogDispatcherQueue",
                _logDispatcher);
            Arbiter.Activate(_logDispatcherQueue, Arbiter.Receive(true, _logPort,
                WriteMessage));

            _logFileName = "DMT_Message_Log_" + String.Format("{0:yyMMddHHmmss}",
                DateTime.Now) + ".log";
        }

        private static void WriteMessage(string messageString)
        {
            using (var sw = File.AppendText(_logFileName))
                sw.WriteLine("[{0:HH:mm:ss tt}] {1}", DateTime.Now, messageString);
        }

        public static void Log(string messageString)
        {
            if (String.IsNullOrEmpty(_logFileName))
                Init();
            _logPort.Post(messageString);
        }

        //Any thread tasks still running?
        private static bool PendingJobs
        {
            get 
            {
                return (_logDispatcher.PendingTaskCount > 0 || 
				_logPort.ItemCount > 0) ? true : false;            
            }
        }

        //Since we are not using background threading we need to add this method to
        //dispose the DQ for application end
        public static void StopLogger()
        {
            while (PendingJobs){Thread.Sleep(100);}
            _logFileName = null;
            _logDispatcherQueue.Dispose();
        }
    }
}

Points of Interest

The CCR doesn't come with the latest version of Visual Studio. It's part of the Microsoft Robotics Studio but instead of downloading the entire studio, I've included the DLL above so you can add it as a reference to your project.

One thing you should notice from the code above is the lack of callback nesting that is involved here, truly a nice model.

Also, if you're using background threading your primary/initial thread will wait on the Dispatcher, even if all Queued posts are completed. You can handle this in a number of ways, such as newing up the Distpatcher without background threading but in this case you'll want to check to make sure all jobs are completed with PendingJobs.

Although this class is fairly simplistic in its design and purpose, you should at least come out seeing the power the CCR holds with just a few lines of code. Step through the code and add some additional ports for fun. The more you understand the CCR the more you'll see how it can improve just about any application you write from here forward.

Happy CCRing!

History

  • 29th October, 2008: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



Comments and Discussions

 
GeneralCCR vsTPL Pin
garagesleeper26-May-09 5:08
garagesleeper26-May-09 5:08 
Hi James,
Thanks for the nice article. How do you compare CCR with TPL. Do they address the same issues(if so why should MS come up with two libraries for the same tasks). Could you come up with any similar & simple descriptions for TPL and also explaining the difference between the two.

thanks & regards,
sasanka
GeneralRe: CCR vsTPL Pin
User 527145413-Jul-09 3:07
User 527145413-Jul-09 3:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.