Friday 25 September 2009

Timing and threads

Jackies carrots
Yesterday was market day and I forgot to take my camera with me. Sorry. But I will include an image from our market that, like Biddy Baxter, I took earlier. This one is from Jackie's famous fruit and veg stall. She's a real quick thinker, so no dithering!

Previous Episode

I said I'd get on to processing inputs from different sources. This is two problems really: one is, there might well be delays in transmission. In this case, it would be better to make regular reports (every 8 secs?) so you don't think your computer has died. You need a timer for this. The other is that your various sources have to be able to add words and counts to the same list without trading on each other and making a mess of the count. This suggests threading to me. Luckily, both timers and threads come from the same library in C#, as they've already forseen you might need both for some tasks. Whatever language you use, you will most likely need a special library for thread, because they go deeper than I want to into the workings of the machine in question. I am NOT a back-end developer (oooh missus!).

Thing is, I had to learn this as I went along, as I haven't even thought about simultaneous processes since Uni (and I'm too old to use that abbreviation, besides it was a Poly then). I turned to the one of my C# books I have only recently started reading again: Pro C# with .NET 3.0 by Andrew Troelsen. I usually refer to the more webby Pro ASP.NET 3.5 in C# 2008 by Matthew McDonald and Mario Szpuszta. Both are Apress books.

So, I now have a slightly different char reader called SlowedDownCharReader. This one uses a private random number to produce slight delays in transmission, which is perhaps a bit more like real life:

      Thread.Sleep(this._random.Next(200));

happens at the beginning of the fetchNextChar method. The random number returned is multiplied by 200 to give some hundredths of a second. This soon mounts up when you only get one char at a time! Note that the word Thread is already coming up. Random delays and timers are all things that affect the current thread of execution. Using these classes requires a using of System.Threading at the head of all relevant files.

Back in the main function, I've written a static setupTimer function. This is where it gets tricky. Since the operation we want to happen every 8 seconds is the WordList method makeReport, we need to create a C# delegate for the Timer to call. This has to be a void function passed a System.Object parameter:

    public delegate void makeReportOp(object state);

Here is the whole setupTimer function:

    static void setupTimer(WordList list, int secsToStart,int intervalSecs)
    {
        int millisecsToStart = secsToStart * 1000;
        int millisecsInterval = intervalSecs * 1000;
        WordList.makeReportOp reporter = new WordList.makeReportOp(list.makeReportCalledBack);
        TimerCallback timeCB = new TimerCallback(reporter);
        Timer everySoOften = new Timer(timeCB, null, millisecsToStart, millisecsInterval);
    }

First of all, the time before the Timer is called and the interval time are passed as seconds and then multiplied by 1000. No one thinks in milliseconds! Now the delegate is created and passed the WordList method to call. I have created a new report method, which sorts the list and writes it to console just as before but writes a short message before and after, so you can see what is going on. The method is locked, so that only one thread can access it (we are envisaging only one wordlist at a time). This message contains the thread number as well, because it is different from the main thread of the program. A TimerCallback delegate is created and passed the reporter delegate. Once that is done, all that is needed is to create a Timer object and pass it the callback, so it knows what to do. It is the Timer which works in its own thread of execution.

This all leads to a strange effect. Every 8 seconds (the interval I chose) a report is made to the console. These get progressively longer as more words get added. At some point, the fetchNextChar will generate its exception, print out a message to the console and stop the main thread. Nothing stops the timer except switching off the console window, so it will carry on printing the same list. I'm told killing threads is a difficult business. But this test case was imagining a continuous process of reporting on different streams coming in, so we won't worry about that.

Next time we'll set up 3-4 threads all putting their words into the same list.






Next Episode

No comments:

Post a Comment