# Tuesday, July 22, 2008

Spartanisch Programmieren - von Stefan Lieser

Stefan Lieser schreibt in seinem Blog, er wäre ein Freund des spartanischen Programmierens. Ich kann mich ihm dort nicht anschließen, da ich lieber Code schreibe, der sich lesen lässt; Variablen bekommen Namen, die auch ein Außenstehender versteht, Code wird kommentiert, es wird mit Freizeilen zur Strukturierung gearbeitet etc. Aber das ist, wie Stefan bereits schrieb, eine persönliche Einstellung. Wenn sie nicht durch Implementierungskonventionen erzwungen oder verboten wird.

Weshalb ich mich jedoch aufgefordert fühle, auf seinen Blogpost zu antworten, ist sein Fast-Exit-Beispiel. Um eine große Verschachtelungstiefe zu vermeiden, schreibt Stefan lieber viele Exits in einer Funktion, statt seinen Code ordentlich zu strukturieren. Zuerst ein schlechtes Beispiel (von Stefan ebenfalls als schlecht angesehen):
public void DoSomething() {
  if (a) {
    if (b) {
      if (c) {
        DoItRealy();
      }
    }
  }
}
Nun seine Verbesserung (Stichwort Fast-Exit), mit der ich noch immer nicht einverstanden bin:
public void DoSomething() {
  if (!a) {
    return;
  }
  if (!b) {
    return;
  }
  if (!c) {
    return;
  }

  DoItRealy();
}

Und nun zwei Arten, die ich persönlich den beiden Vorangegangenen (nicht uneingeschränkt, aber meistens) vorziehen würde:
public void DoSomething() {
  if ( ( a )
    && ( b )
    && ( c ) )
  {
    DoItRealy();
  }
}

public void DoSomething() {
  if (!a) 
  {
    Log("Not a");
  }
  else if (!b)
  {
    Log("Not b");
  }
  else if (!c)
  {
    Log("Not c");
  }
  else
  {
    Log("All requirements complied.");
    DoItRealy();
  }
}

Tuesday, July 22, 2008 6:01:54 PM (W. Europe Standard Time, UTC+01:00) #    Comments [1] | Trackback
# Tuesday, June 24, 2008

InternalsVisibleToAttribute

Ein nettes Fundstück: Ich habe gerade ein wenig mit der Testfunktionalität von VS2008 herumgespielt, um ein paar Änderungen an der Blog-Engine zu testen, da bin ich auf das nette Attribut InternalsVisibleToAttribute gestoßen. Mit diesem Attribut kann man einer Assembly Zugriff auf internal deklarierte Methoden einer anderen Assembly gewähren. Sehr nettes Feature für Unit Tests.

Tuesday, June 24, 2008 10:35:27 PM (W. Europe Standard Time, UTC+01:00) #    Comments [0] | Trackback
# Monday, June 23, 2008

Multithreading - Teil 2 - System.Threading.Monitor

Im zweiten Teil der unbestimmt langen Reihe Multithreading in .NET befasse ich mich mit der Klasse System.Threading.Monitor.

System.Threading.Monitor

Der Monitor ist das Objekt, was sich bei genauerer Betrachtung hinter einem lock-Statement verbirgt. Die Details dazu können im ersten Teil nachgelesen werden. Die Verwendung ist der eines lock-Statements sehr ähnlich. Man verwendet den Monitor stets in Verbindung mit einem Objekt, welches verriegelt werden soll. Der daraus resultierende IL-Code unterscheidet sich ebenfalls nicht von dem eines lock-Statements.
private void monitorNotationExample( object lockObject )
{
    Monitor.Enter( lockObject );

    //Critical Section: Do something

    Monitor.Exit( lockObject );
}
Nach der Critical Section muss allerdings im Gegensatz zum lock-Statement die Verriegelung explizit wieder freigegeben werden. Dies macht den Monitor etwas fehleranfälliger als das lock-Statement. Er hat allerdings auch einige ganz entscheidende Vorteile.

Vorteile der Klasse Monitor gegenüber lock

Die Klasse Monitor stellt neben der Funktion Enter noch die Funktion TryEnter bereit, um eine exklusive Sperre für eine Critical Section zu bekommen. Die Funktion TryEnter ist doppelt überladen und liefert jeweils einen Booleschen Wert zurück.

Monitor.TryEnter

Der Aufruf der Funktion Monitor.TryEnter(Object) versucht, eine exklusive Sperre auf das übergebene Objekt zu erlangen. Schlägt dies fehl, weil bereits ein anderer Thread eine Sperre auf dieses Objekt hält, liefert die Funktion ein false zurück. Konnte die Sperre erlangt werden, wird true zurückgegeben.

Monitor.TryEnter (Object, Int32)

Die erste Überladung der Funktion mit dem zusätzlichen Parameter vom Typ Int32 dient dazu, einen Timeout anzugeben. Dieser Timeout wird Anzahl der Millisekunden übergeben, die maximal versucht werden soll, eine exklusive Sperre für das Objekt zu erlangen. Wird zu einem beliebigen Zeitpunkt innerhalb der Zeitspanne die Sperre erlangt, gibt der Aufruf true zurück. Wird der Timeout erreicht, kehrt der Aufruf mit false zurück. Dieser Aufruf ermöglicht es also, eine bestimmte Zeit auf eine Sperre zu warten. Der Rückgabewert muss also in jedem Fall ausgewertet werden. Außerdem muss man bei der Verwendung der Funktion Monitor.TryEnter (Object, Int32) darauf achten, dass eine geeignete Strategie vorhanden ist für den Fall, dass keine Sperre registriert werden konnte.

Monitor.TryEnter (Object, TimeSpan)

Die zweite Überladung verlangt als zweiten Parameter keinen Int32, der die Anzahl der Millisekunden für den Timeout angibt, sondern eine Zeitspanne vom Typ System.TimeSpan. Mit dieser zweiten Überladung ist es also möglich, die ersten beiden Funktionsaufrufe nachzubilden. Entweder wird als Zeitspanne wirklich eine Zeitspanne übergeben, was der ersten Überladung entspräche, oder es wird Timeout.Infinite übergeben, was dem Aufruf der Funktion Monitor.TryEnter(Object) entspräche.

Einige Beispiele

Um die Funktionsweise der einzelnen Methoden der Monitor-Klasse zu verdeutlichen, werde ich einige Beispiele anführen. Beginnen wir mit einfacheren Verwendung des Monitors. Wir nehmen einen Konsolenanwendung und erweitern diese mit der Klasse AsyncTest. In dieser Klasse sind zwei Methoden enthalten, Sync1() und Sync2(). Beide Methoden greifen auf dasselbe lock-Objekt zu. nämlich lock1.
class Program
{
    static void Main( string[] args )
    {
        AsyncTest test = new AsyncTest( );
        Thread thread1 = new Thread( new ThreadStart( test.Sync1 ) );
        Thread thread2 = new Thread( new ThreadStart( test.Sync2 ) );

        thread1.Start( );
        thread2.Start( );
        Console.ReadLine( );
    }
}

public class AsyncTest
{
    private object lock1 = new object( );

    public void Sync1( )
    {
        Monitor.Enter(lock1);
        for ( int i = 1; i <= 20; i++ )
        {
            Console.Write( "1 {0}|", i );
            Thread.Sleep( 20 );
        }
        Monitor.Exit( lock1 );
    }

    public void Sync2( )
    {
        Monitor.Enter( lock1 );
        for ( int i = 1; i <= 20; i++ )
        {
            Console.Write( "2 {0}|", i );
            Thread.Sleep( 20 );
        }
        Monitor.Exit( lock1 );
    }
}
Die Ausgabe der beiden Threads erfolgt sequenziell, wie bereits im ersten Teil erklärt.



Schauen wir uns im nächsten Beispiel die Funktionsweise der Methode TryEnter an. Thread 2 in der Main-Routine führt nun die Methode Sync3 in der Klasse AsyncTest aus. Diese versucht über den Aufruf von Monitor.TryEnter(lock1) eine Sperre auf das Objekt zu bekommen.
class Program
{
     static void Main( string[] args )
     {
         AsyncTest test = new AsyncTest( );
         Thread thread1 = new Thread( new ThreadStart( test.Sync1 ) );
         Thread thread2 = new Thread( new ThreadStart( test.Sync3 ) );

         thread1.Start( );
         thread2.Start( );
         Console.ReadLine( );
     }
}

public class AsyncTest
{
    private object lock1 = new object( );

    public void Sync1( )
    {
        Monitor.Enter(lock1);
        for ( int i = 1; i <= 20; i++ )
        {
            Console.Write( "1 {0}|", i );
            Thread.Sleep( 20 );
        }
        Monitor.Exit( lock1 );
    }


    public void Sync3( )
    {
        if ( Monitor.TryEnter( lock1 ) )
        {
            Console.WriteLine( Environment.NewLine + "Lock achieved." );
            Monitor.Exit( lock1 );
        }
        else
        {
            Console.WriteLine( Environment.NewLine + "Lock cannot be achieved." );
        }
    }
}
Ergibt:



Die Ausgabe zu diesem Beispiel entspricht der Beschreibung der Methode Monitor.TryEnter(). Es wird versucht, eine Sperre auf das übergebene Objekt zu registrieren. Schlägt dies fehl, kehrt die Methode mit false zurück. Hätte eine Sperre registriert werden können, wäre true zurückgegeben worden.
Betrachten wir das Verhalten der Methode Sync3() nun einmal mit Übergabe eines Timeouts. Dieser soll 100 Millisekunden lang sein. Die neue Methode nennen wir Sync4() und verdrahten sie in der Main-Methode auf den zweiten Thread:
public void Sync4( )
{
    if ( Monitor.TryEnter( lock1, 100 ) )
    {
        Console.WriteLine( Environment.NewLine + "Lock achieved." );
        Monitor.Exit( lock1 );

    }
    else
    {
        Console.WriteLine( Environment.NewLine + "Lock cannot be achieved." );
    }
}



Wie man sehen kann, kehrt die Methode Sync4 etwas später zurück als Sync3 im vorigen Beispiel, kann jedoch immer noch keine Sperre registrieren. Betrachten wir die Funktion Sync1 genauer, wird auch schnell klar, warum. Sie dauert bei 20 Schleifendurchläufen mit jeweils einem Sleep von 20 Millisekunden mindestens 400 Millisekunden.
Setzen wir nun also den Timeout in Sync4 auf 1000 Millisekunden.



Wie man sehen kann, war der Timeout nun so lang, dass Sync1 vollständig abgearbeitet und die Sperre freigegeben werden konnte, bevor der Timeout abgelaufen war. Der zweite Thread konnte seine Sperre erfolgreich registrieren.

Platzierung der lock-Freigabe Monitor.Exit()

Wie man an Hand der Funktionen Sync3 und Sync4 erkennen kann, habe ich die Freigabe der Sperre nicht an das Ende der Funktion gestellt, sondern an das Ende des Zweigs, der bei erfolgreicher Registrierung der Sperre angesprungen wird. Wird nämlich die Funktion Exit(object) auf ein Objekt aufgerufen, für welches der aufrufende Thread keine Sperre registriert hat, bekommt man von der Runtime eine SynchronizationLockException vor den Bug geknallt, die man dann behandeln darf.
 


Um dies zu vermeiden (und um logischeren Code zu schreiben) sollte man allerdings den von mir gewählten Weg gehen und die Sperre nur dann freigeben, wenn sie auch wirklich registriert wurde. Außerdem sollte man die Freigabe der Sperre in einem finally-Block notieren, um auf alles vorbereitet zu sein. Auch wenn irgendwo innerhalb der Critical Section eine Exception geworfen wird, wird so wenigstens die Sperre freigegeben und die Chance erhöht, dass sich die Anwendung nicht in einem "Deadlock "aufhängt".
Die richtige Notation für den Monitor wäre also:
public void Sync6( )
{
    if ( Monitor.TryEnter( lock1, 1000 ) )
    {
        try
        {
            //Critical section
        }
        finally
        {
            Monitor.Exit( lock1 );
        }
    }
    else
    {
        //else-Fall behandeln
    }
}
Und wem bei der Betrachtung dieser Methode das C# Keyword using in den Kopf kommt, der ist ganz nah bei dem, was sich die .NET-Entwickler gedacht haben. Ändert man den Timeout von 1000 Millisekunden auf Timeout.Infinite und lässt den else-Zweig weg, entspricht diese Methode dem lock-Statement. Womit nun der Unterschied zwischen den drei Methoden Enter, TryEnter und Exit des Monitors sowie dem lock-Statement hinreichend beschrieben sein sollte.

Fassen wir noch einmal zusammen:
  • Das lock-Statement wartet, bis es eine Sperre registrieren konnte. Die Freigabe der Sperre erfolg in einem "finally"-Block (die geschweifte Klammer zu des lock-Blocks).
  • Enter versucht eine Sperre zu registrieren und kehrt sofort zurück. Entweder ist die Sperre registriert (Rückgabe true) oder eben nicht (Rückgabe false). Auf jeden Fall muss sich der Programmierer Gedanken im das Exception Handling machen.
  • TryEnter erweitert Enter um die Möglichkeit, einen bestimmten Zeitraum auf eine Sperre zu warten. Entweder wird die Sperre in diesem Zeitraum registriert (Rückgabe true) oder die Zeit läuft ab (Rückgabe false). Auch hier muss der Programmierer sich um das Exception Handling selbst kümmern.
Im nächsten Teil werde ich die restlichen Funktionen der Klasse Monitor beleuchten: Monitor.Wait(), Monitor.Pulse() und Monitor.PulseAll(). Bis dahin freue ich mich auf Feedback und/oder Anregungen.

Monday, June 23, 2008 8:36:36 PM (W. Europe Standard Time, UTC+01:00) #    Comments [0] | Trackback
# Thursday, June 19, 2008

C# XML Documentation

During my nightly coding session working on my gps class library for my smart phone I started to use the xml decomentation tags see and seealso. Later on after the "nightly build" I had several warnings that the compiler could not resolve the types provided inside these tags. But thanks to Alan Dean and his great artivle about XML documentation in C# my usual sleep amount wont be decreased as much as I feared 10 minutes before.

Thursday, June 19, 2008 10:58:44 PM (W. Europe Standard Time, UTC+01:00) #    Comments [0] | Trackback
# Monday, June 09, 2008

.Net Micro Framework Team announces .Net Micro Framework 3.0

Last friday, June 6th, the Microsoft .Net Microframework Team announced a new version 3.0 of the .Net Micro framework. Several cool features are supported, for example a file system, toch screen support and the development environment was changed to VS2008. Have a look at the complete list of new features. Now I hope that Device Solutions will update the Tahoe firmware as soon as possible so that I can profit from the new features.

Monday, June 09, 2008 11:14:54 AM (W. Europe Standard Time, UTC+01:00) #    Comments [0] | Trackback
# Sunday, June 08, 2008

Multithreading - Teil 1 - das lock-Statement

Bereits seit einiger Zeit sind Multi-Core-Prozessoren für den normalen Konsumenten erschwinglich. In Servern werden bereits seit einigen Jahren Multiprozessorsysteme eingesetzt. Jedoch kommt mir immer wieder Code unter, der sich strikt an einen Kern bindet, weil keine Operation asynchron ausgeführt wird. Ich persönlich vertrete die Meinung, dass  allein aus Gründen der User Experience mehrere Threads eingesetzt werden sollen. Welcher Benutzer sieht es schon gern, wenn er auf einen Button drückt, und die Anwendung für einige Sekunden zu einer weißen Fläche wird? In Gesprächen mit Entwicklern höre ich jedoch immer wieder das Argument, dass Multithread-Programmierung ja so kompliziert sei und man es lieber nicht verwendet, um keine Fehler zu machen. Denn das Debugging von Multithreaded-Code ist nicht so trivial wie bei Singlethreaded-Code. Daher möchte ich in einer unbestimmt langen Reihe einige Aspekte des Multithreading beleuchten.

lock

Beginnen möchte ich mit dem C#-Keyword lock. Das lock-Statement ist nur in C# verfügbar. Es wird ähnlich dem using-Statement verwendet:

lock(obj)
{
//Do something synchronized }

lock wird also auf ein Objekt aufgerufen. Der Code innerhalb des Blocks wird nur aufgeführt, wenn das der lock-Aufruf zurückgekehrt ist. Es ist also sichergestellt, dass der Code innerhalb des Blocks immer nur von einem Thread ausgeführt wird. Der Blockinhalt wird auch Critical Section genannt.

Wie verwendet man lock?

Die Syntax für die Nutzung von lock ist denkbar einfach. Allerdings sind einige Einschränkungen bei der Verwendung zu beachten.

Reference-Type

lock kann nur auf Reference-Types aufgerufen werden. Dies hängt damit zusammen, dass lock eigentlich eine Maskierung für

Monitor.Enter(lockobject);

ist.

Auf welches Objekt soll das lock aufgerufen werden?

Oft sieht man Konstrukte wie

lock(this){ }

Diese verletzen jedoch oft die Design Guidelines für Multithreadprogrammierung. Und zwar in den folgenden Fällen:

  • lock(this){ } kann zu einem Problem werden, wenn die Instanz des Objekts public ist, also öffentliche Zugriffe erlaubt.

  • lock(typeof(MyType)){ } ist ebenfalls problematisch, wenn MyType öffentlich zugänglich ist.

  • lock("mylock") { } bedeutet, dass alle lock-Statements, die so geschrieben werden,
    dasselbe Lock-Objekt benutzen, da es sich um einen String handelt.

lock sollte also immer auf dedizierte private Objekte aufgerufen werden. Soll eine Critical Section über alle Instanzen eines Objekts geschützt sein, definiert man das lock-Objekt als static.

private static object lockObj = new object();

private void foo()
{
lock(lockObj)
{
//Critical section } }

Was passiert bei einem lock?

Nehmen wir eine Methode einer Windows-Forms-Anwendung. Auf dem Formular ist ein Button button1 platziert. Klickt man diesen an, soll sich der Text des Formulars nach „LOCKED“ ändern. Es ergibt sich folgende Funktion:

private void button1_Click(object sender, EventArgs e)
{
lock (this.lockObject)
{
this.Text = "LOCKED";
}
}

Was macht der Compiler aus dieser Funktion? Schauen wir uns die erzeugte Intermediate Language an:

.method private hidebysig instance void button1_Click(object sender, class [mscorlib]System.EventArgs e) cil managed
{
.maxstack 2
.locals init (
[0] object CS$2$0000)
L_0000: nop
L_0001: ldarg.0
L_0002: ldfld object lock1.Form1::lockObject
L_0007: dup
L_0008: stloc.0
L_0009: call void [mscorlib]System.Threading.Monitor::Enter(object)
L_000e: nop
L_000f: nop
L_0010: ldarg.0
L_0011: ldstr "LOCKED"
L_0016: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Control::set_Text(string)
L_001b: nop
L_001c: nop
L_001d: leave.s L_0027
L_001f: ldloc.0
L_0020: call void [mscorlib]System.Threading.Monitor::Exit(object)
L_0025: nop
L_0026: endfinally
L_0027: nop
L_0028: ret
.try L_000f to L_001f finally handler L_001f to L_0027
}

Wie man sieht, wird das lock-Statement zu einem System.Threading.Monitor.Enter(lockObject) aufgelöst. Der entsprechende Aufruf der Methode System.Threading.Monitor.Exit(lockObject) wird in einen finally-Block eingefasst. Es kann also innerhalb der Critical section passieren, was will, der Monitor wird  freigegeben. Dies ist einer der großen Vorteile des lock-Statements. Der Entwickler muss sich nur sehr wenige Gedanken um die korrekte Freigabe des Monitors machen, da dies der Compiler für ihn erledigt.

Allerdings verbirgt sich hier auch einer der Nachteile des lock-Statements. Der Compiler löst das lock-Statement in ein Monitor.Enter(lockObject) auf. Das kann unter Umständen dazu führen, dass der Aufruf nie zurückkehrt, man also in eine Deadlock-Situation gerät. Um dies zu vermeiden, verwendet man besser Monitor.TryEnter(object, TimeSpan). TryEnter versucht für die angegebene Zeitspanne ein lock auf das Objekt zu erlangen. Schlägt dies fehl, kehrt die Methode mit false zurück. Der Nachteil dieses Aufrufs ist jedoch, dass der Entwickler sich nun selbst um das Fehlerhandling kümmern muss. Folgender Codeblock kann also statt des lock-Statements verwendet werden:

if ( !Monitor.TryEnter( lock2, TimeSpan.FromSeconds( 1 ) ) )
{
    throw new ApplicationException( "Unable to claim lock on object {0}", lock2.ToString() );
}
try
{
    //Critical section
}
finally
{
    Monitor.Exit( lock2 );
}

In diesem Fall liegt die Freigabe des Monitors jedoch ganz auf Seiten des Entwicklers. Außerdem muss er sich Gedanken darüber machen, wie die Applikation darauf reagiert, wenn der Monitor nicht in der vorgegebenen Zeitspanne erlangt werden kann. Deadlocks sind so jedoch ausgeschlossen.

Einige Beispiele

Zuerst schauen wir uns an, wie sich zwei Methoden verhalten, die von unterschiedlichen Threads aus aufgerufen werden. Eine dieser Methoden ist durch ein lock verriegelt:

class Program
{
static void Main( string[] args )
{
AsyncTest test = new AsyncTest( );
Thread thread1 = new Thread(new ThreadStart(test.SyncLock1));
Thread thread2 = new Thread( new ThreadStart( test.UnsyncLock1 ) );

thread1.Start( );
thread2.Start( );
Console.ReadLine( );
}
}

public class AsyncTest
{
private object lock1 = new object( );

public void SyncLock1( )
{
lock ( lock1 )
{
for ( int i = 1; i <= 20; i++ )
{
Console.Write( "SyncLock1 {0}|", i );
Thread.Sleep( 20 );
}
}
}

public void UnsyncLock1( )
{
for ( int i = 1; i <= 20; i++ )
{
Console.Write( "UnsyncLock1 {0}|", i );
Thread.Sleep( 20 );
}
}
}

Auf der Konsole wird folgendes ausgegeben:


Man kann also sehen, dass die beiden Threads sich nicht von dem lock des einen beeindrucken lassen. Warum auch, schließlich wird keiner durch das lock tangiert.

Ändern wir das Programm etwas ab und fügen eine Methode hinzu die ebenfalls durch ein lock verriegelt ist:

class Program
{
    static void Main( string[] args )
    {
        AsyncTest test = new AsyncTest( );
        Thread thread1 = new Thread(new ThreadStart(test.SyncLock1));
        Thread thread2 = new Thread( new ThreadStart(test.SyncLock2 ) );

        thread1.Start( );
        thread2.Start( );
        Console.ReadLine( );
    }
}

public class AsyncTest
{
    private object lock1 = new object( );
    private object lock2 = new object( );

    public void SyncLock1( )
    {
        lock ( lock1 )
        {
            for ( int i = 1; i <= 20; i++ )
            {
                Console.Write( "SyncLock1 {0}|", i );
                Thread.Sleep( 20 );
            }
        }
    }

    public void SyncLock2( )
    {
        lock ( lock2 )
        {
            for ( int i = 1; i <= 20; i++ )
            {
                Console.Write( "SyncLock2 {0}|", i );
                Thread.Sleep( 20 );
            }
        }
    }
}

Die Konsolenausgabe gleicht der des ersten Beispiels:


Denn auch hier ist es so, dass beide Methoden unabhängige Locks verwenden, sodass keine die andere beeinflusst.

Verriegeln wir nun die zwei Methoden mit demselben lock-Objekt:

class Program
{
    static void Main( string[] args )
    {
        AsyncTest test = new AsyncTest( );
        Thread thread1 = new Thread(new ThreadStart(test.SyncLock1));
        Thread thread2 = new Thread( new ThreadStart( test.SyncLock3 ) );

        thread1.Start( );
        thread2.Start( );
        Console.ReadLine( );
    }
}

public class AsyncTest
{
    private object lock1 = new object( );
    
    public void SyncLock1( )
    {
        lock ( lock1 )
        {
            for ( int i = 1; i <= 20; i++ )
            {
                Console.Write( "SyncLock1 {0}|", i );
                Thread.Sleep( 20 );
            }
        }
    }

    public void SyncLock3( )
    {
        lock ( lock1 )
        {
            for ( int i = 1; i <= 20; i++ )
            {
                Console.Write( "SyncLock3 {0}|", i );
                Thread.Sleep( 20 );
            }
        }
    }
}

Die Methoden werden nun nacheinander abgearbeitet:



Was bedeutet dies nun?

Auf ein Objekt kann nur ein lock (intern ja eigentlich ein Monitor) vergeben werden. Verwenden verschiedene Methoden verschiedene lock-Objekte, beeinflussen sich diese Methoden nicht. Verwenden sie das gleiche lock-Objekt, warten alle Threads, die die Critical Section betreten wollen, bis sie Einer nach dem Anderen das lock auf das Objekt erhalten. Damit einher geht natürlich die Notwendigkeit, dass ein Thread, der eine Critical Section betritt, beim Verlassen dieser das Lock-Objekt wieder freigibt, sodass ein anderer Thread die Critical Section betreten kann.

Links

Ausblick

Im nächsten Teil werde ich das Synchronisationsobjekt Monitor beleuchten. Bis dahin freue ich mich über Rückmeldungen zu diesem Teil.

Sunday, June 08, 2008 3:54:14 PM (W. Europe Standard Time, UTC+01:00) #    Comments [0] | Trackback
# Friday, May 23, 2008

UnitTesting mit Visual Studio 2008

Robert Mühsig hat auf dem Code-Inside Blog einen wunderbaren Post über den Einstieg in Unit Testing mit Visual Studio 2008 geschrieben. Ich persönlich bin bisher ebenfalls von den von Robert angeführten Gründen noch kein Fan von Unit Testing, weiß jedoch, dass es die Qualität von Software verbessert (gegenüber keinen Unit Tests). Angetriggert durch seinen Post werde ich mich nun auch einmal mit dem der Thematik auseinander setzen. Der Einstieg scheint nicht so schwer zu sein (dank der mittlerweile hervorragenden Integration in Visual Studio) und verlieren kann man auch nichts.

Friday, May 23, 2008 8:41:56 AM (W. Europe Standard Time, UTC+01:00) #    Comments [0] | Trackback
# Thursday, May 08, 2008

Neues Spielzeug gefällig?

Ich hoffe, dass mein Handyvertrag jetzt schneller ausläuft und mein Provider des Vertrauens das kleine Juwel in sein Portfolio übernimmt. Man sehe uns staune... das iPhone ist ja wohl ein Witz dagegen. Darauf läuft ja noch nicht einmal ein .NET Framework ;)

Thursday, May 08, 2008 10:35:36 PM (W. Europe Standard Time, UTC+01:00) #    Comments [2] | Trackback
# Wednesday, May 07, 2008

Powershell TCP Listener

The project I'm currently working on is an embedded device without any graphical interface capability. The only ways to get some information out is the NIC or a serial port. There is also a CAN-Bus interface, but as far as my company developed the device it is better to not base our debugging capabilities on a potentially buggy part of the system. Out first debug out was implemented as a serial output tracer. As the day comes closer that out hardware prototypes will arrive, the higher the need to port the tracing over to the NIC as far as the final hardware won't have a serial port on it.
So last week the network tracer was check in into source control. Now, how to read these information?
Windows ships with Hyper Terminal. But this isn't very comfortable and you manually have to reestablish a lost connection. In my today's lunch break I wrote a small powershell script that listens to the network socket. At the moment I'm porting it to C# to add some more features.

But here is the first part, a small and simple powershell script to listen to a network socket. But please let me clarify that this is code snippet is NOT the way code. It was a fast hack to get it running. There is no error handling and ressources are not freed gracefully as it has to be terminated with ctrl + c. In clear words: This is a sample on how to receive data from a network socket.

$socket = new-object System.Net.Sockets.TcpClient("172.16.170.123", 9950)
if($socket -eq $null) { return; }
$stream = $socket.GetStream()
$buffer = new-object System.Byte[] $socket.ReceiveBufferSize
$encoding = new-object System.Text.AsciiEncoding

while($true)
{
   if($stream.DataAvailable)
   {
      $read = $stream.Read($buffer, 0, $socket.ReceiveBufferSize)  
      write-host -n ($encoding.GetString($buffer, 0, $read))
   }
}

Wednesday, May 07, 2008 8:47:07 PM (W. Europe Standard Time, UTC+01:00) #    Comments [0] | Trackback
# Sunday, April 13, 2008

Mit Powershell das EventLog eines Remoterechners überwachen

Mein Blog wird auf einem Windows 2003 Server gehostet. Da ich gerne wissen möchte, was dort so alles passiert, habe ich mir ein kleines Powershell-Script geschrieben, welches mir einmal pro Tag die Eventlog-Einträge des letzten Tages per E-Mail zusendet:

$sys = Get-Eventlog -list | Foreach-Object -process{Get-Eventlog $_.Log} | ?{$_.TimeGenerated -gt [DateTime]::Now.AddDays(-1)} |  ConvertTo-Html
$msg = New-Object Net.Mail.MailMessage("from@my.mail", "to@my.mail", "Daily Eventlog summary", $sys)
$msg.IsBodyHTML = $true
$smtp = New-Object NetMail.SmtpClient("mailserver.my.mail")
$smtp.Send($msg)

Was macht das Script genau?


Zuerst wird per
Get-Eventlog -list
eine Liste der auf dem System vorhandenen Eventlogs erstellt. Das Ergebnis wird an das Foreach-Object-Cmdlet gepipt, welches für jedes Element der Liste die Einträge abfragt:
Foreach-Object -process{Get-Eventlog $_.Log}
Die daraus resultierende Liste von Einträgen wird dann gefilter. Es sollen nur die Einträge weiterverarbeitet werden, die innerhalb des letzten Tages erstellt wurden:
?{$_.TimeGenerated -gt [DateTime]::Now.AddDays(-1)}
Diese Zeile kann auch als
Where-Object {$_.TimeGenerated -gt [DateTime]::Now.AddDays(-1)}
geschrieben werden, aber ? ist einfach etwas schneller.
Die gefilterten Einträge werden dann als HTML
ConvertTo-HTML
in der Variablen $sys gespeichert.
Im nächsten Schritt wird ein System.Net.Mail.MailMessage-Objekt erstellt, welches die HTML-Liste $sys der Eventlog-Einträge als Nachrichtentext übergeben bekommt.
$msg = New-Object Net.Mail.MailMessage("from@my.mail", "to@my.mail", "Daily Eventlog summary", $sys)
Die MailMessage-Instanz ist nötig, da wir eine HTML-Mail versenden wollen.
$msg.IsBodyHTML = $true
Möchten wir PlanText versenden, können wir den Nachrichtentext auch der $smtp.Send()-Methode übergeben.
Um die Mail per smtp.Send versenden zu können, muss erst der SmtpClient instanziiert werden. Im Konstruktor bekommt er den Mailserver übergeben, über der die Nachricht gesendet werden soll.
$smtp = New-Object NetMail.SmtpClient("mailserver.my.mail")
$smtp.Send($msg)


Im nächsten Schritt werde ich daraus ein kleines, konfigurierbares C#-Programm erstellen, das zum Beispiel verschiedene Ereignisquellen ausfiltern kann.

Sunday, April 13, 2008 11:44:37 AM (W. Europe Standard Time, UTC+01:00) #    Comments [0] | Trackback
# Tuesday, April 08, 2008

String.Format mit geschweifter Klammer

Mit Hilfe der String.Format-Methode können ja bekanntlich formatierte Einsetzungen in einen String vorgenommen werden. Im Ursprungsstring werden dazu Platzhalter in der Form {0}, {1}, etc eingefügt. Sind allerdings im Formatstring, als dem String, in den die neuen Teile eingesetzt werden, geschweifte Klammern enthalten, werden diese als Formatierungszeichen betrachtet. Aufgefallen ist mir dies bei der Formatierung der Zeichenkette:
#ifndef _BLABLUB_H_
#define _BLABLUB_H_

#  ifdef __cplusplus
  extern "C" {
#  endif /* __cplusplus */
BLABLUB sollte dabei durch den entsprechenden Namen der Headerdatei ersetzt werden. Allerdings hagelte es mit folgendem FormatString bei jedem Versuch, die formatierte Ausgabe zu erzeugen, eine FormatException.
public static string HeaderExklusionStart = "#ifndef {0}"
    + Environment.NewLine
    + "#define {0}"
    + Environment.NewLine
    + Environment.NewLine
    + "#  ifdef __cplusplus"
    + Environment.NewLine
    + "  extern \"C\" {"
    + Environment.NewLine 
    + "#  endif /* __cplusplus */";
Um den Fehler zu beheben, müssen einfach geschweifte Klammern, die ausgegeben werden sollen und somit nicht als Formatierungsanweisungen zu interpretieren sind, doppelt eingefügt werden:
+ "  extern \"C\" {{"

Auf den Fehler hingewiesen hat mich der Artikel Kombinierte Formatierung im MSDN. Prädikat: Wertvoll.
Tuesday, April 08, 2008 11:14:50 AM (W. Europe Standard Time, UTC+01:00) #    Comments [0] | Trackback

Fehlerkorrektur: String auf ASCII-Reinheit prüfen

In meinem gestrigen Post String auf ASCII-Reinheit prüfen hat sich ein Fehler eingeschlichen. Die öffentliche Eigenschaft Encoding des StreamWriters ist ReadOnly. Um das Encoding des StreamWriters festzulegen, muss dieses im Constructur übergeben werden:
sourceWriter = new System.IO.StreamWriter( sourceFS, Encoding.ASCII );

Tuesday, April 08, 2008 9:00:49 AM (W. Europe Standard Time, UTC+01:00) #    Comments [0] | Trackback
# Monday, April 07, 2008

String auf ASCII-Reinheit prüfen

Momentan liegt mein beruflicher Schwerpunkt eher auf der Programmiersprache C im Embedded Umfeld. Da dies jedoch nicht meine präferierte Sprache ist und außerdem die Arbeit (Webserverprogrammierung, CGI-Funktionen, etc) auf Grund der Vielzahl von ähnlichen CGI-Funktionen ein bisschen nach Automatisierung riecht, habe ich begonnen, einen Codegenerator zu schreiben.
Ein paar Worte zur Erklärung. Wir haben eine Anwendung mit zentraler Pseudodatenbank, die alle Programmteile als Quelle und Senke nutzen. Ca. 80% der Datenpunkte sollen per Web-Frontend editierbar sein. Um den Programmierer des Web-Frontends nicht mit den Interna des Microcontrollers zu belasten, stellen wir die Datenpunkte über CGI-Funktionen bereit. Somit muss für jeden Datenpunkt eine ähnlichlautende Zugriffsfunktion in C erstellt werden. Lediglich der Datentyp ändert sich. Die Pflege der Datenpunkte erfolgt in einer Excel-Datei, die auch externen Firmen zur Verfügung gestellt wird.
Da es sich bei dem generierten Code um C-Code handelt und die eingesetzte Entwicklungsumgebung keine Quelltexte in Unicode verarbeiten kann, muss ASCII-Code generiert werden. C# verarbeitet jedoch 2 Byte breite Chars und schreibt liebend gern Unicode. Dies wäre an sich kein Problem, da man einem StreamWriter ja über dessen öffentliche Eigenschaft Encoding die Codierung der Daten vorgeben kann. Jedoch sind, warum auch immer, in den Bezeichnern der Datenpunkte Umlaute vorhanden. Diese können jedoch nicht einfach so in ASCII konvertiert werden, da sie dort nicht definiert sind. So kam schnell der Gedanke nach einem eigenen Konverter oder Filter auf.
Aber wie?

Möglichkeit 1 - Regular Expression Match
System.Text.RegularExpressions.Regex regex = 
     new System.Text.RegularExpressions.Regex( "[^\x00-\x7F]" );
 if ( regex.IsMatch( testString ) )
 {
     //Nicht-ASCII-Zeichen gefunden
 }
Mit dieser Regular Expression werden alle Zeichen gefunden, deren Byte-Repräsentation nicht im Bereich 00 bis 7F liegt. Man könnte nun im If-Block ein paar Methoden zur Ersetzung von beispielsweise 'ä' einsetzen. Allerdings werden dann nur diese Zeichen ersetzt, alle anderen müssen anderweitig behandelt werden. Dadurch wird der Programmablauf inkonsistent.
Alternativ könnten diese Zeichen nicht weiter beachtet werden. Dies würde dann entsprechende Lücken in der Ausgabe hinterlassen.
Wird der If-Block jedoch nicht angesprungen, ist der String garantiert frei von Nicht-ASCII-Zeichen.

Möglichkeit 2 - Regular Expression Grouping
Ändert man den regulären Ausdruck von oben ein wenig ab, kann man die gefundenen Zeichen gruppieren. Dies ermöglicht es, eine Match-Collection zu verwenden, die weitergehende Möglichkeiten bietet. Die Syntax für des regulären Ausdrucks für die Gruppierung wäre:
System.Text.RegularExpressions.Regex regex = 
    new System.Text.RegularExpressions.Regex( "(^\x00-\x7F)" );
System.Text.RegularExpressions.MatchCollection matches =
    regex.Matches( testString );
foreach ( System.Text.RegularExpressions.Match match in matches )
{
    //Nicht-ASCII-Zeichen-Gruppe gefunden
}
Dabei stellt das Objekt Match eine ganze Reihe nützlicher Funktionen bereit, so zum Beispiel die Position des Matches im Ursprungs-String oder die Länge des Matches. Es werden nämlich mit dieser Möglichkeit auch Gruppen wie im Beispiel "Hallööö Welt" die Gruppe "ööö" als ein zusammenhängender Treffer erkannt.

Möglichkeit 3 - Die Klasse Encoding
Die Klasse Encoding stellt verschiedene Möglichkeiten bereit, um mit Zeichen und Zeichenketten zu hantieren. Bei dem oben dargestellten Problem war dies mein erster Anlaufpunkt. Jedoch bin ich nach einigen Monaten C-Programmierung hier einem falschen Pferd aufgesessen :). Man beachte nachfolgende Zeile C#-Code und komme bitte nicht auf die Idee, dies irgendwo zu verwenden:
Encoding.ASCII.GetString( (byte[])testString, 0, testString.Length );
Die Methode GetString der Klasse Encoding.ASCII erwartet als ersten Parameter ein Byte-Array. Was würde man also in C machen? Richtig. Wie oben geschrieben, castet man seine Zeichenkette, eigentlich ja nur ein Char-Array in ein Byte-Array. Die Datentypen sind ja jeweils 1 Byte lang. 1 Byte? Ein Char in C#? Und da steckt der Fehler. In C# ist ein Char 2 Byte lang. Stichwort Unicode. Glücklicherweise meckert dies bereits der Compiler an.
Wie dem auch sei. Der Versuch mündete schließlich in folgendem Qullcode:
string testString = "Halööö Welt. Hähähäh!!!";
byte[] byteArray = Encoding.ASCII.GetBytes( testString );
Console.WriteLine( Encoding.ASCII.GetString( byteArray, 0, byteArray.Length ) );
Dieser Codeschnippsel spuckt dann, wie erwartet, einen ASCII-String aus: Hall??? Welt. H?H?H?!!! Wer damit leben kann...

Fazit
Glücklicher Weise übermittelte mir plötzlich ein Kollege die frohe Botschaft, dass die Bezeichner in den nächsten Tagen auf englische Bezeichner umgestellt werden. Also Umlaute ade. Das ist mir in dieser Situation gar nicht unpassend, da mir keine triviale Lösung für das Problem der Konvertierung eines Unicode-Strings in einen ASCII-String bekannt ist. Schließlich müssen einige Dinge beachtet werden, zum Beispiel die CurrentCulture, da wahrscheinlich ein ö in Deutschland einfach durch oe ersetzt werden kann. Ob das im türkischen ebenso möglich ist, weiß ich nicht.

Dieser Beitrag soll zum einen Anregungen geben, wie die Lösung eines solchen Problems angegangen werden kann. Zum anderen ist es ein Aufruf: Falls jemand dieses Problem schon einmal lösen musste, wäre ich (wahrscheinlich nicht ausschließlich) sehr dankbar, seinen Weg kennenzulernen.

Monday, April 07, 2008 8:02:49 PM (W. Europe Standard Time, UTC+01:00) #    Comments [0] | Trackback
# Friday, March 28, 2008

DasBlog Mobile support

Today I was browsing around the internet a bit with my mobile phone and just wanted to check what was going on in my logs as I recognized that dasBlog has a great support for mobile browsers. So, quite a bit puzzled at first, I afterwards asked myself how I could miss that feature. So I checked it out and it seems to be in dasBlog since version 1.9. Really darn cool feature. Again one more point for this great bloging engine.

In consideration on what is going on on the dasBlog mailing list I hope that there will be a future for dasBlog or something similar to this (dasText or whatever is it called). I hope that I then can take some time to also do some work for the new project.

Friday, March 28, 2008 7:55:29 PM (W. Europe Standard Time, UTC+01:00) #    Comments [0] | Trackback
# Tuesday, February 19, 2008

Microsoft announces DreamSpark

Today Microsoft announced the DreamSpark program. For students from United States, the United Kingdom, China, Germany, France, Finland, Spain, Sweden, Switzerland and Belgium there is now a program to get Microsoft products without charge. In the second wave more countries are served.

The current list of products is:
  • Visual Studio 2008 Professional
  • Visual Studio 2005 Professional
  • XNA Game Studio 2.0
  • 12-month free membership in the XNA Creators Club
  • Expression Studio (Expression Web, Expression Blend, Expression Design, Expression Media)
  • Windows Server Standard Edition (2005, 2008 from next semester on)
  • SQL Server 2005 Developer Edition
  • [Update] Virtual PC 2007 [/Update]
For everyone who looks puzzled like me; here Bill Gates is talking about free software, students and technologies.

The DreamSpark Program is hosted here and the initial blog entry is from Veni, Vidi, Velcro.

Finally, I was headed towards this great announcement by heise news.

Tuesday, February 19, 2008 11:02:23 PM (W. Europe Standard Time, UTC+01:00) #    Comments [0] | Trackback
# Tuesday, January 22, 2008

Blog about .NET Compact Framework

Today my attention was invited by Robert to Christan Helle's blog. He is deep into the .NET Compact framework and seems to have some very interesting blog posts over there I hope to get through this weekend. I immediately added his blog to my favourite newsreader and also to the blogroll. So, if you are interested in mobile or embedded development, have a look at his site.

Tuesday, January 22, 2008 10:47:22 PM (W. Europe Standard Time, UTC+01:00) #    Comments [0] | Trackback